原文链接:QRowTable表格控件(三)-效率优化之-合理使用QStandardItem
一、开心一刻
砖家在河边看到两只乌龟缩着一动不动,问一农民:“它们在干吗?”。
农民说:“在比赛!”。
砖家不解:“动都没动过,比什么赛?”。
农民:“在比装死!”。
砖家:“可是壳上有甲骨文的那只,早就死了啊?”。
这时,一只乌龟猛然探出头来骂道:“MD,死了也不吭一声!”。
突然另一只也伸出头来:“傻子!砖家的话你也信,你输了 !”。
二、概述
最近换了一家新单位,工作的内容也发了一些变化。接触了一些大牛,也让我对Qt有了一个新的认识。
不看源码真他妈不行呀
这不今天就给大家说一说我最近工作中遇到的一个坑,而这个坑只有看了源码后才明白。
上一篇QRowTable表格控件(二)-红涨绿跌文章讲到了我们怎么往表格中添加数据,并且是了一个简单的股票组件。可以存放各种行情数据、持仓和订单等等。
下面问题就来了,我这个demo中的数据只有不到10行,当你真的把这个控件投入的生产环境时就会发现,demo就是demo,它就是个demo而已。
博主自己大概测试了下把数据调到10000行,等了几分钟界面还没有出来,就放弃了。
测试代码如下:
int rate = 10000;
model->setRowCount(rate * itemVec.size());
for (int j = 0; j < rate; ++j)
{
for (int i = 0; i < itemVec.size(); ++i)
{
const OptionalMarketItem & info = itemVec.at(i);
QStandardItem * item_price = new QStandardItem;
item_price->setText(QString::number(info.price));
item_price->setData(int(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
model->setItem(i, 0, item_price);
...
}
}
既然代码性能不行,我们当然需要去找更好的实现方式了,总不能就这么上线吧。
于是乎,有了如下代码,30000行数据1-2s即可初始化完毕,震惊脸。
int rate = 10000;
model->setRowCount(rate * itemVec.size());
for (int j = 0; j < rate; ++j)
{
for (int i = 0; i < itemVec.size(); ++i)
{
const OptionalMarketItem & info = itemVec.at(i);
int row = i + j * itemVec.size();
QModelIndex index = model->index(row, 0);
model->setData(index, QString::number(info.price), Qt::DisplayRole);
model->setData(index, int(Qt::AlignRight | Qt::AlignVCenter),Qt::TextAlignmentRole);
}
}
我槽,上述两种书写方式有球区别,怎么会差别如此之大,下面让我为大家细细道来。
三、效果展示
以下是红涨绿跌效果图,demo中展示了30000数据,应该算是比较多,可以满足大多数的应用场景。
腹黑版
四、QStandardItem
1、QStandardItem是什么鬼
Qt的帮助文档是一个好东西,打开assisant.exe,搜索QStandardItem类,可以搜索如下提示信息。
什么意思呢!
为了阅读起来更流畅,我这里就行中文内容的意译。
虽然英文解释很多,但是意译成中文后就很简单了,毕竟帮助文档要说的很清晰、场景囊括的会比较全一些
意译:QStandardItem是一个数据结构,他可以存储一个cell的各种信息,比如文本、图标、是否可选、字体、别景色、前景色等等。并且QStandardItem可以有孩子和兄弟,他是为model提供数据存储的节点。
这里我在补充一些内容,让大家对QStandardItem右更进一步的了解。
QTableView:作为表格cell时,有一个作为根节点的QStandardItem,其他节点都是QStandardItem节点的孩子节点,并且都是兄弟节点(这里暂时不考虑多列的情况)。
QTreeView:作为树节点cell时,有一个作为根节点的QStandardItem,其他节点都是他的孩子节点,但是其他节点也可以作为父节点存在(这里暂时不考虑多列的情况)。
2、性能分析
a、QStandardItem构造慢?
简单了解QStandardItem对象后,下面开始从代码上分析性能问题到底出现在了哪里。
//优化前代码
QStandardItem * item_price = new QStandardItem;
item_price->setText(QString::number(info.price));
item_price->setData(int(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
model->setItem(i, 0, item_price);
//优化后代码
int row = i + j * itemVec.size();
QModelIndex index = model->index(row, 0);
model->setData(index, QString::number(info.price), Qt::DisplayRole);
model->setData(index, int(Qt::AlignRight | Qt::AlignVCenter),Qt::TextAlignmentRole);
仔细比较以上代码,优化前的diamante是我们自己构造了QStandardItem,然后设置数据并存储到QStandardItemModel中,而优化后的代码我们直接把数据通过QStandardItemModel进行了设置。
这两种方式到底有何区别???
解决这种问题,Qt给我们提供了很好的问题解决方式,直接跟踪源码即可。想要把Qt了解透彻,源码是唯一的途径。其他什么各种搜索引擎都弱爆了。
如上图所示,跟踪Qt的源码发现,当我们通过Model设置数据项时,Qt内部也是为我们构造了一个QStandardItem对象,然后把数据放到这个对象上的。
说明QStandardItem对象的构造并不是性能所在,性能问题还需要进一步分析。
很重要:Qt的Model