相关文章推荐
苦闷的围巾  ·  const (C++) | ...·  1 月前    · 
霸气的沙滩裤  ·  java - ...·  1 年前    · 
茫然的烈马  ·  新建Android ...·  1 年前    · 

QTreeView处理大量数据(使用1000万条数据,每次都只是部分刷新)

如何使 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::DisplayRole) 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;

QVariant headerData(intsection, Qt::Orientationorientation, int role =Qt::DisplayRole)const; 显示树视的标题, section 表示列,从 0 开始, orientation 表示标题的方向(水平还是垂直), role 表式标题栏显示的方式,当 role 的角色为 Qt::DisplayRole 时,表示显示文本,当然还有其他角色,大家可以参考 Qt 开发手册。

示例代码:

QVariant CMyModel::headerData(int section, Qt::Orientation orientation, int role) const

if (role == Qt::DisplayRole && orientation == Qt::Horizontal)

return pData->headerData(section);

return QVariant();

显示水平标题,其中 pData 是定义的一个数据类的对象,在这里把该类命名为 CData,headerData 来取出要显示的数据。

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::DisplayRole)

return pData->getData(row, col);

return QVariant();

通过 getData 来获取要显示的数据,该数据方在我们的文件里,每次只需要读取我们想要显示的数据,不需要把所有的数据都放到内存,从而节省了内存空间,这样就解决了上面讲的第一个问题。

int rowCount(const QModelIndex &parent = QModelIndex())const; 大家不难猜出该函数是返回该父节点下有多少个子节点,还是来看示例代码吧:

int CMyModel::rowCount(const QModelIndex &parent)const

return pData->rowCount();

为了简单起见,这里不考虑父节点,认为任何节点都存在 rowCount() 个节点。

int columnCount(const QModelIndex &parent = QModelIndex())const; 返回父节点有多少列,示例代码:

int CMyModel::columnCount(const QModelIndex &parent)const

return pData->colCount();

接下来看 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 等视图。

【转载】: https://blog.csdn.net/rabinsong/article/details/8452946

QTreeView处理大量数据(使用1000万条数据,每次都只是部分刷新)如何使QTreeView快速显示1000万条数据,并且内存占用量少呢?这个问题困扰我很久,在网上找了好多相关资料,都没有找到合理的解决方案,今天在这里把我的解决方案提供给朋友们,供大家相互学习。我开始使用的QTreeWidget 控件来显示我的数据,发现该控件在显示10000行以下的数据还可以应付的过来,但超过100...
使用 QT做HMI开发,因为GPU或者CPU的资源有限,为了得到更流畅的交互效果,局部 刷新 的方法是大家都一直寻找的解决方案,限制 部分 刷新 帧率,把资源更多的留给实时性要求高的。 Qt5以后的版本,都推荐 使用 GPU去渲染,提高渲染的效果,即 使用 scene graph这个机制去渲染。 使用 Qt的Scene Graph来开发应用,要点是批量渲染。这是由OpenGL的特性决定的,因为通过OpenGL,
1、void QWidget::update ( const QRegion & rgn ) 这个update本身就能够只跟新指定区域的; 2、 使用 QImage类,操作一个图片的单一的像素点,然后用个定时器,不断的让你的图片在label里显示;即将所有东西都画在一个影子位图中,然后只在重画的时候画影子位图 3、参考文档主页,examples下,Graphics View下的 C
QWebView 重新加载页面,页面只有图像内容有改变,但是图像文件名没变,QWebView 默认是有缓存的,所以直接 使用 QWebView::load() 重新加载,页面图片会从缓存中读取,不会更新,需要清除缓存再加载, 使用 QWebSettings::clearMemoryCaches() 清除缓存, 使用 如下: ui->webView->settings()->cle...
您好,关于 QTreeView 代理如何获取过滤后的 数据 ,可以通过以下步骤实现: 1. 获取 QTreeView 的模型对象,例如:QAbstractItemModel *model = ui->treeView->model(); 2. 获取过滤后的 数据 ,可以 使用 QSortFilterProxyModel类进行过滤,例如:QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(model); proxyModel->setFilterRegExp(QRegExp("过滤条件")); QModelIndex index = proxyModel->index(row, column, QModelIndex()); 3. 获取过滤后的 数据 ,可以 使用 QVariant类型进行获取,例如:QVariant data = proxyModel->data(index, Qt::DisplayRole); 希望能够帮助到您。