原文链接: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的调用机制调用获取数据时给他返回即可。

关键点

  1. 重写Model,自己存储数据
  2. 重写data接口,返回数据

1、自己存储数据

自己存储数据有一个好处,那就是我们在给Model设置数据时,最大的性能损耗就是数据拷贝的过程,仔细想想这个是不是都不是问题。

上述代码中的TradeOrderInfoList这个接口提就是我们自己定义的一个容器接口,方便存储我们的表格数据,当视图绘制时,会从这里拿数据。

2、重写data接口

数据已经准备完毕,接下里就是View如何优雅的拿到数据并绘制了,这里我们重点讲述怎么拿数据,如何绘制是QStyledItemDelegate这个类的事,感兴趣的可以自己研究研究。

仔细查看Model的版主文档们就会发现有一个data接口函数,他的声明可能像下面这样

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;

们的任务就是重写这个接口,返回指定索引上的指定类型数据

  1. index:表格cell的索引,包含有行和列序号
  2. 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接口更新下。

数据源重写好以后,再试试我们的性能是不是杠杠滴。

四、比较

本篇文章应该是实现表格功能的最后一篇文章了,可以满足大多数的产品需求。

后续可能还会陆续出一些更友好的交互优化,敬请期待。

下面是一个表格,包含了传统的表格数据源和重写后的表格数据源优劣比较。

比较项目 传统方式 重写Model
难易程度 简单 复杂
代码里
性能
推荐度 两颗星 五颗星

五、相关文章

  1. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等

  2. Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格

  3. 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)

  4. 超级实用的属性浏览器控件--QtTreePropertyBrowser

  5. Qt之表格控件蚂蚁线

  6. QRowTable表格控件-支持hover整行、checked整行、指定列排序等

  7. QRowTable表格控件(二)-红涨绿跌

  8. QRowTable表格控件(三)-效率优化之-合理使用QStandardItem


值得一看的优秀文章:

  1. 财联社-产品展示
  2. 广联达-产品展示
  3. Qt定制控件列表
  4. 牛逼哄哄的Qt库
如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


最新文章

  1. mysql交互式连接&amp;非交互式连接
  2. 我的第一篇blog
  3. mysql禁用autocommit,以及遇到的问题
  4. 【五子棋AI循序渐进】——整合完成
  5. 在linux中搭建git服务器
  6. 内部类中class声明地方不同,效果不一样
  7. mexopencv问题:Invalid MEX file GLIBCXX_3.4.15 error
  8. .net LINQ and PLINQ
  9. Unable to chmod /system/build.prop.: Read-only file system
  10. javascript的BOM,DOM对象
  11. Beta第六天
  12. JS面向对象使用面向对象进行开发
  13. 关于linux上postgresql的一些理解
  14. python实现单例模式的三种方式及相关知识解释
  15. 【linux】常用命令之用户管理
  16. Scripts may close only the windows that were opened by it
  17. python数据结构与算法第十七天【概率算法】
  18. Leading and Trailing LightOJ - 1282 (取数的前三位和后三位)
  19. elasticsearch 常用命令(一)
  20. PHP 之 Ci框架下隐藏index.php

热门文章

  1. LeetCode :1.两数之和 解题报告及算法优化思路
  2. Docker 架构原理及简单使用
  3. Linux(Ubuntu)安装Swift和Swiftlint
  4. 牛客多校训练第八场C.CDMA(思维+构造)
  5. vue面试题整理vuejs基础知识整理
  6. 用 bat 文件实现 excel 周报复制
  7. MySQL学习随笔记录
  8. MacOS VSCode 安装 GO 插件失败问题解决
  9. SBT安装及命令行打包spark程序
  10. (三十二)c#Winform自定义控件-表格