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

    关键点

    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. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


  • 相关阅读:
    Linux (Ubuntu)安装ssh
    Linux (Ubuntu)提示ifconfig:找不到命令
    Docker介绍
    微服务用到的技术
    移动端BI的设计
    Cobbler Web管理(二)
    基于CentOS7环境下的Cobbler部署介绍(一)
    使用google-perftools优化nginx内存管理提升性能
    解决 nginx 配置TLS1.2无效,总是TLS1.0的问题
    在nginx中将爬虫过来的请求转到指定的后端服务
  • 原文地址:https://www.cnblogs.com/swarmbees/p/11490909.html
Copyright © 2020-2023  润新知