QRowTable表格控件(四)-效率优化之-优化数据源
目录
原文链接:qrowtable表格控件(四)-效率优化之-优化数据源
一、开心一刻
一程序员第一次上女朋友家她妈板着脸问 :你想娶我女儿,有多少存款?
程序员低了下头:五百!
她妈更鄙视了:才五百块,买个厕所都不够!
程序员忙说:不是人民币!
她妈:就算是美元,还是不够买厕所!
程序员:其实是比特币!
她妈:哇,贤婿,我给你买只大龙虾去
二、问题分析
前边已经写了3篇关于表格控件的功能,分别是qrowtable表格控件-支持hover整行、checked整行、指定列排序等、qrowtable表格控件(二)-红涨绿跌和qrowtable表格控件(三)-效率优化之-合理使用qstandarditem,这三篇文章主要是围绕实现核心功能来讲述的一般实现方式,当数据量多大时就会出现性能问题。
既然出现问题,当然是需要解决的。本篇文章就来讲述怎么处理大量数据的情况。
首先我们先来分析下上述几种实现方式为什么会比较消耗时间,首先代码量也不大,在代码里随机打几个断点,我们就会发现,代码在循环构造qstandarditem这个结构中耗费的时间比较久,并且当for循环出现上万次循环时尤为明显。
找到问题后,就是想办法怎么可以更少的调用构造qstandarditem这个流程,当然了qt也给我们提供了很好的解决方案,那就是重写数据源(model)。
三、重写数据源
qt中包含有经典的mvc模式,比如我们经常使用的qstandarditemmodel、qtableview和qstyleditemdelegate,当我们要实现一个高效的表格控件时,重写这3个类基本就可以完成我们所需要的功能。
当然了qt还提供了了一层数据缓存层qsortfilterproxymodel,这个类可以帮助我们更好的实现排序、模糊搜索功能
本篇文章这里只讲解重写数据源,关于其他两个类的重写前面文章中应该有所讲述,这里不再过多解释。
下面一起来看下数据源的重写方式,我们这里选择继承自qstandarditemmodel这个类来实现我们的数据源,这里是一个偷懒的方式,正常情况下是需要重写qabstractitemmodel类,如果重写qabstractitemmodel类的话,那么就需要重写更多的接口。
class qrowmodel : public qstandarditemmodel { q_object public: explicit qrowmodel(qobject * parent = 0); ~qrowmodel(); public: //设置数据源 void setsourcedata(const tradeorderinfolist & data); ... protected: virtual qvariant headerdata(int section, qt::orientation orientation, int role = qt::displayrole) const override; virtual qvariant data(const qmodelindex &index, int role = qt::displayrole) const override; virtual void sort(int column, qt::sortorder order /* = qt::ascendingorder */) override; private: ... tradeorderinfolist itemlist; qcolor m_checkedcolor = qcolor("#4f4f4f"); mutable std::map <int, int> m_alignmentlist;//列对其方式 friend class qrowtable; };
上次代码是重写model类的头文件,其中有一些不相干的代码我选择了隐藏,重写model最重要的就是需要我们自己去存储数据,并且在qt的调用机制调用获取数据时给他返回即可。
关键点
- 重写model,自己存储数据
- 重写data接口,返回数据
1、自己存储数据
自己存储数据有一个好处,那就是我们在给model设置数据时,最大的性能损耗就是数据拷贝的过程,仔细想想这个是不是都不是问题。
上述代码中的tradeorderinfolist这个接口提就是我们自己定义的一个容器接口,方便存储我们的表格数据,当视图绘制时,会从这里拿数据。
2、重写data接口
数据已经准备完毕,接下里就是view如何优雅的拿到数据并绘制了,这里我们重点讲述怎么拿数据,如何绘制是qstyleditemdelegate这个类的事,感兴趣的可以自己研究研究。
仔细查看model的版主文档们就会发现有一个data接口函数,他的声明可能像下面这样
qvariant data(const qmodelindex &index, int role = qt::displayrole) const q_decl_override;
们的任务就是重写这个接口,返回指定索引上的指定类型数据
- index:表格cell的索引,包含有行和列序号
- role:表格数据类型,每一个cell上都包含有一系列键值对,方便存储单元格上的各种数据,比如说前景色、背景色、字体、位置、高亮色、背景画刷等等。
qvariant qrowmodel::data(const qmodelindex &index, int role) const { if (qt::decorationrole == role) { int r = index.row(); int c = index.column(); if (r >= itemlist.size()) { return ""; } const tradeorderinfo & info = itemlist.at(r); switch (c) { case 0: return qpixmap(stock_helper::getcurrencyicon(info.market, info.symbol).c_str()); default: ""; break; } } else if (qt::foregroundrole == role) { int r = index.row(); int c = index.column(); if (r >= itemlist.size()) { return ""; } const tradeorderinfo & info = itemlist.at(r); switch (c) { case 4://"方向" if (info.action.compare("sell") == 0) { return qcolor("#218df2"); } else { return qcolor("#ff4a4a"); } default: return qcolor("#dddddd"); } } else if (qt::displayrole == role) { //自己从model中拿数据给view //"名称" int r = index.row(); int c = index.column(); if (r >= itemlist.size()) { return ""; } const tradeorderinfo & info = itemlist.at(r); switch (c) { case 0://"名称" return stock_helper::orderdisplayname(&info); case 1://"代码" return stock_helper::orderdisplaysymbol(&info, m_straccount); case 2://"成交量" 数字居右 return qstring::number(info.totalquantity); case 3://"成交均价" 数字居右 return stock_helper::pricedisplayname(info.symbol, info.market, info.sectype, info.avgfillprice); case 4://"方向" if (info.action.compare("sell") == 0) { return qui_load_string(tts_order_dir_sell); } else { return qui_load_string(tts_order_dir_buy); } default: ""; break; } } return qstandarditemmodel::data(index, role); }
别忘啦,当数据源发生变化的时候使用setsourcedata接口更新下。
数据源重写好以后,再试试我们的性能是不是杠杠滴。
四、比较
本篇文章应该是实现表格功能的最后一篇文章了,可以满足大多数的产品需求。
后续可能还会陆续出一些更友好的交互优化,敬请期待。
下面是一个表格,包含了传统的表格数据源和重写后的表格数据源优劣比较。
五、相关文章
值得一看的优秀文章:
如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!
很重要--转载声明
本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者: or twowords
如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。