物探论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 871|回复: 0

[Envi] QTreeView处理大量数据

[复制链接]
发表于 2013-8-12 11:31:53 | 显示全部楼层 |阅读模式
如何使QTreeView快速显示1000万条数据,并且内存占用量少呢?这个问题困扰我很久,在网上找了好多相关资料,都没有找到合理的解决方案,今天在这里把我的解决方案提供给朋友们,供大家相互学习。我开始使用的QTreeWidget 控件来显示我的数据,发现该控件在显示10000行以下的数据还可以应付的过来,但超过10000条,就明显感觉到屏幕刷新就会有卡的现象,而且占据内存很大,虽然操作起来简单方便,但灵活性没有QTreeView强大。因为我要显示的数据量是非常大的,甚至过1000万,因此,采用QTreeWidget来显示,很显然不能满足性能要求,所以打算采用QTreeView来显示,不罗嗦了,赶快进入正题了,下面讲讲我是怎么通过QTreeView来快速显示1000万条数据的吧!    1.通过从文件里面读取要显示的数据,交给QTreeView来显示,从而不用把数据一次性读到内存,就可以解决内存占用大的问题。    2.我们知道数据显示是通过刷新来实现的,通过刷新时,每次只刷新屏幕可见区域,其他部分不用刷新的方法,从而解决速度显示慢的问题。解决了上面的两个问题,显示1亿条数据都不会有任何问题,而且显示速度和内存占有量与显示1000条数据相当,听起来很诱人啊,下面是我是怎么通过QTreeView来解决这两个问题的:1.重载QAbstractItemModel中的如下函数:           QVariant headerData(int section, Qt::Orientation orientation,         int role = Qt:isplayRole) const;        QVariant data(const QModelIndex &index, int role) const;        int rowCount(const QModelIndex &parent = QModelIndex()) const;              int columnCount(const QModelIndex &parent = QModelIndex()) const;        QModelIndex index(int row, int column,         const QModelIndex &parent = QModelIndex()) const;        QModelIndex parent(const QModelIndex &index) const;    (1)QVariant headerData(intsection, Qt::Orientationorientation, int role =Qt:isplayRole)const;显示树视的标题,section表示列,从0开始,orientation表示标题的方向(水平还是垂直),role表式标题栏显示的方式,当role的角色为Qt:isplayRole时,表示显示文本,当然还有其他角色,大家可以参考Qt开发手册。示例代码:         QVariant CMyModel::headerData(int section, Qt::Orientation orientation, int role) const        {            if (role == Qt:isplayRole && orientation == Qt::Horizontal)            {                 return pData->headerData(section);            }            return QVariant();        }    显示水平标题,其中pData是我定义的一个数据类的对象,在这里我把该类命名为CData,headerData来取出要显示的数据。(2)QVariant data(const QModelIndex &index,int role)const;显示数据,index表示树节点索引,树中的每个节点都有一个对应的该索引,当index = QModelIndex()时,表示该节点是根节点,否则为非根节点。index中存放了该节点在同存节点中的位置信息(行和列),以及节点的特殊信息,如index.internalPointer(),这是一个指针,我们可以通过该指针保存我们想要的节点信息,角色同上。示例代码:         QVariant CMyModel::data(const QModelIndex &index, int role) const        {             if (!index.isValid())                 return QVariant();             int row = index.row();             int col = index.column();             if(role == Qt:isplayRole)             {                  return pData->getData(row, col);             }             return QVariant();        }    通过getData来获取要显示的数据,该数据方在我们的文件里,每次只需要读取我们想要显示的数据,不需要把所有的数据都放到内存,从而节省了内存空间,这样就解决了上面讲的第一个问题。(3)int rowCount(const QModelIndex &parent = QModelIndex())const;大家不难猜出该函数是返回该父节点下有多少个子节点,还是来看示例代码吧:        int CMyModel::rowCount(const QModelIndex &parent)const        {             return pData->rowCount();        }    为了简单起见,这里不考虑父节点,认为任何节点都存在rowCount()个节点。(4)int columnCount(const QModelIndex &parent = QModelIndex())const;返回父节点有多少列,示例代码:        int CMyModel::columnCount(const QModelIndex &parent)const        {             return pData->colCount();        }(5)接下来看QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;的实现:               QModelIndex CMChModel::index(int row, int column, const QModelIndex &parent) const        {            return createIndex(row, column, NULL);        }通过该函数创建节点的索引,我这里简单一点,只创建一层节点,若大家要创建多层节点,则要通parent索引里的数据(如internalPointer())来创建对应的节点,通过createIndex的第3个参数来向节点传入指定的索引数据,由于我这里不需要创建多层节点,所以我传入NULL。那麽我们怎么建立节点的父子关系呢,聪明的你肯定想到了吧,QModelIndex parent(const QModelIndex &index) const;就是建立父子节点的父子关系的,如果只有一层节点,该函数无须重载,至此我们的显示数据模型已经实现了,接下来就是要把这个模型通过视图来表现出来(QTreeView)。我们看看QTreeView是怎么来显示我们上面建立的模型的,看一段简单的代码,大家就明白了:       QTreeView treeView;        CMyModel *pModel = new CMyModel();       treeView.setModel(pModel);       treeView.show();2.是不是很简单,到这里通过QTreeView来处理大量的数据的实现方式差不多讲完了,当你按照上面的方式准备处理你的大批量数据时,你就会发现显示10000行数据还是会卡,这是什么原因呢?其实这个也困扰我很久,网上也没有找到相关资料,没办法啊,只有啃QTreeView实现的源代码,实际上QTreeView确实是显示可见部分数据(每次显示1000行数据,按理论上来说1000行足以占据计算机屏幕,这样一来不管你数据量是多大,我始终只取1000行数据,所以1亿条数据与1000条数据显示速度是一样的,只要你一次只读出要显示的数据,内存占有量也是一样的),既然问题都解决了,那麽为什么还会有卡的现象呢?经过进一步研究QTreeView源代码,最后发现耗时的地方是QTreeView第一次刷新的时候会计算每一行的行高,这样刷新时,就要遍历所有行数据,原来卡是出在这个地方啊,那麽应该怎么解决呢?实现方法很简单,就是上面的代码多加一行,treeView.setUniformRowHeights(true);这样一来就不会刷新计算所有行的行高了,至此用QTreeView显示大批量数据问题得到解决。最后再补充一下,该实现方式可以适应其他QTableView, QListView等视图。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|物探论坛 ( 鄂ICP备12002012号 微信号:iwutan )

GMT+8, 2020-10-29 12:59 , Processed in 0.064517 second(s), 15 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表