简述
前面简单介绍过Qt的模型/视图框架,提到了Qt预定义的几个model类型:
QStringListModel:存储简单的字符串列表
QStandardItemModel:可以用于树结构的存储,提供了层次数据
QFileSystemModel:本地系统的文件和目录信息
QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel:存取数据库数据
一般情况下满足需求了,不过有时候需要一些定制功能,或者是大量数据下对性能和开销比较注重,觉得自带的model无用功能太多效率比较低,这时候自定义model就比较适合了。
我使用自定义model 同时出于这两方面需要,既为了性能也为了特殊功能。
参考资料
豆子《Qt学习之路2》中的几篇关于自定义model的文章:
- 自定义model之一: 自定义只读模型
- 自定义model之二: 自定义可编辑模型
- 自定义model之三: 布尔表达式树模型
效果
本篇文章写的费了点功夫,为了演示本章内容,花了几个小时的时间整理代码和示例。
因为技术都应用在我的项目里,实际所用的model实现了很多特殊功能,非常复杂,我要提炼出一个简单可读的demo。
如图,分别演示了以常规的 QStandardItemModel 和使用自定义的model的效果。
示例中只使用了10W行的数据量级
运行程序你就会发现,常规model在初始化tree的过程就比自定义model慢很多,更可怕的是,它所占用的内存开销是自定义model的数倍甚至数十倍!数据量越大内存差距越明显。
这里以10个一级节点班级,每个班级1W个学生,共10W条记录的数据量测试:
QStandardItemModel 方法程序占用总内存大概160多M,而自定义model 占用的30多M。
而Qt一个简单窗口程序本身有20多M内存。
可见自定义model显示这10W条记录基本没使用多少内存,如果考虑百万、千万级别的数据,不使用自定义model或比较有效的优化方法,内存将很快耗尽。
构造演示数据
我演示的例子为一级节点班级、二级节点学生信息。
其中学生信息原始数据只有姓名、三门课成绩,需显示的列多一些,包含:
班级/姓名、语文、数学、外语、总分、平均分、是否合格、是否评优
其中后面几列是根据学生成绩计算得出的:
所有课成绩都>60则合格,所有课成绩都>90则优秀。
定义数据类型:班级、学生
//学生信息
typedef struct _STUDENT{
QString name; //姓名
int score1; //语文成绩
int score2; //数学成绩
int score3; //外语成绩
_STUDENT()
{
name = "";
score1 = score2 = score3 = 0;
}
}STUDENT,*PSTUDENT;
//班级信息
typedef struct _CLASS{
QString name; //班级
QVector<STUDENT*> students;
_CLASS()
{
name = "";
}
}CLASS;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//初始化模拟数据:学生成绩
//10个班级、每个班级10000个学生,共10W行记录
int nClass = 10;
int nStudent = 10000;
for(int i=0;i<