QTreeView自定义model:大数据量显示--性能和内存的优化

QTreeView⾃定义model:⼤数据量显⽰--性能和内存的优化简述
前⾯简单介绍过Qt的模型/视图框架,提到了Qt预定义的⼏个model类型:
QStringListModel:存储简单的字符串列表
QStandardItemModel:可以⽤于树结构的存储,提供了层次数据
QFileSystemModel:本地系统的⽂件和⽬录信息
QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel:存取数据库数据
⼀般情况下满⾜需求了,不过有时候需要⼀些定制功能,或者是⼤量数据下对性能和开销⽐较注重,觉得⾃带的model⽆⽤功能太多效率⽐较低,这时候⾃定义model就⽐较适合了。
我使⽤⾃定义model 同时出于这两⽅⾯需要,既为了性能也为了特殊功能。
参考资料
⾖⼦《》中的⼏篇关于⾃定义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)
{
lm5117ui->setupUi(this);
玻璃胶配方//初始化模拟数据:学⽣成绩
//10个班级、每个班级10000个学⽣,共10W⾏记录
样本制作
int nClass = 10;
int nStudent = 10000;
for(int i=0;i<nClass;i++)
{
CLASS* c = new CLASS;
c->name = QString("class%1").arg(i);
for(int j=0;j<nStudent;j++)
{
STUDENT* s = new STUDENT;
s->name = QString("name%1").arg(j);
s->score1 = s->score2 = s->score3 = (j%10)*10;
c->students.append(s);
}
mClasses.append(c);
}
}
其中mClasses为存放模拟数据的变量:
QVector<CLASS*> mClasses;  //模拟数据
QStandardItemModel 常规model
void MainWindow::on_btn1_clicked()
{
//1,QTreeView常⽤设置项
QTreeView* t = ui->treeView;
//    t->setEditTriggers(QTreeView::NoEditTriggers);            //单元格不能编辑
触摸屏手机t->setSelectionBehavior(QTreeView::SelectRows);        //⼀次选中整⾏
t->setSelectionMode(QTreeView::SingleSelection);        //单选,配合上⾯的整⾏就是⼀次选单⾏//    t->setAlternatingRowColors(true);                      //每间隔⼀⾏颜⾊不⼀样,当有qss时该属性⽆效    t->setFocusPolicy(Qt::NoFocus);                        //去掉⿏标移到单元格上时的虚线框
//2,列头相关设置
t->header()->setHighlightSections(true);                //列头点击时字体变粗,去掉该效果
t->header()->setDefaultAlignment(Qt::AlignCenter);      //列头⽂字默认居中对齐
t->header()->setDefaultSectionSize(100);                //默认列宽100
t->header()->setStretchLastSection(true);              //最后⼀列⾃适应宽度
t->header()->setSortIndicator(0,Qt::AscendingOrder);    //按第1列升序排序
//3,构造Model
QStringList headers;
headers << QStringLiteral("班级/姓名")
<< QStringLiteral("语⽂")
<< QStringLiteral("数学")
<< QStringLiteral("外语")
<< QStringLiteral("总分")
<< QStringLiteral("平均分")
<< QStringLiteral("是否合格")
<< QStringLiteral("是否评优");
QStandardItemModel* model = new QStandardItemModel(ui->treeView);
model->setHorizontalHeaderLabels(headers);
foreach (CLASS* c, mClasses)
{
//⼀级节点:班级
QStandardItem* itemClass = new QStandardItem(c->name);
model->appendRow(itemClass);
foreach (STUDENT* s, c->students)
{
//⼆级节点:学⽣信息
int score1 = s->score1;
int score2 = s->score2;
int score3 = s->score3;
int nTotal = score1 + score2 + score3;
int nAverage = nTotal/3;
bool bPass = true;
if(score1 < 60 || score2 < 60 || score3 < 60)
{
//任意⼀门课不合格则不合格
bPass = false;
}
bool bGood = false;
if(score1 >= 90 && score2 >= 90 && score3 >= 90)
{
//每门课都达到90分以上评优
bGood = true;
}
QList<QStandardItem*> items;
QStandardItem* item0 = new QStandardItem(s->name);
QStandardItem* item0 = new QStandardItem(s->name);
QStandardItem* item1 = new QStandardItem(QString::number(score1));
QStandardItem* item2 = new QStandardItem(QString::number(score2));
QStandardItem* item3 = new QStandardItem(QString::number(score3));
QStandardItem* item4 = new QStandardItem(QString::number(nTotal));
QStandardItem* item5 = new QStandardItem(QString::number(nAverage));
QStandardItem* item6 = new QStandardItem(bPass ? "合格" : "不合格");
QStandardItem* item7 = new QStandardItem(bGood ? "优秀" : "-");
items << item0 << item1 << item2 << item3 << item4 << item5 << item6 << item7;
itemClass->appendRow(items);
}
}
/
/4,应⽤model
t->setModel(model);
}
⾃定义model
Qt提供⼀个基础的model类QAbstractItemModel,前⾯⼏种常⽤model也基本从此类⽽来。 我们写⼀个⾃定义的TreeModel,继承⾃该类,实现⾥⾯的⼀些重载函数:
#include "TreeItem.h"
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include "define.h"
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeModel(QStringList headers,QObject *parent = 0);
~TreeModel();
//以下为⾃定义model需要实现的⼀些虚函数,将会被Qt在查询model数据时调⽤
//headerData: 获取表头第section列的数据
//data: 核⼼函数,获取某个索引index的元素的各种数据
//      role决定获取哪种数据,常⽤有下⾯⼏种:
//      DisplayRole(默认):就是界⾯显⽰的⽂本数据
//      TextAlignmentRole:就是元素的⽂本对齐属性
/
/      TextColorRole、BackgroundRole:分别指⽂本颜⾊、单元格背景⾊
//flags: 获取index的⼀些标志,⼀般不怎么改
//index: Qt向你的model请求⼀个索引为parent的节点下⾯的row⾏column列⼦节点的元素,在本函数⾥你需要返回该元素的正确索引
//parent:获取指定元素的⽗元素码图
//rowCount: 获取指定元素的⼦节点个数(下⼀级⾏数)
//columnCount: 获取指定元素的列数
QVariant headerData(int section, Qt::Orientation orientation,int role = Qt::DisplayRole) const override;
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
public:
TreeItem *itemFromIndex(const QModelIndex &index) const;
烷基铝TreeItem *root();
private:
QStringList mHeaders;  //表头内容
TreeItem *mRootItem;    //根节点
};
这些函数基本作⽤在注释内注明了,主要需要根据⾃⼰的情况写好data函数,其它的内容可以参考我的⽰例代码,略微调整。 其中TreeItem 为我们⾃定义的指代⼀个节点的类:

本文发布于:2024-09-23 12:28:40,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/165429.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据   定义   班级   内存
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议