QSortFilterProxyModel和延迟填充的树视图
QSortFilterProxyModel and lazily populated treeviews
我已经通过子类化QAbstractItemModel实现了一个延迟填充的树视图。实现看起来像:
https://gist.github.com/gnufied/db9c4d805e2bb24d8c23
(我不是在内联中粘贴代码,以免干扰消息传递)
它基本上是存储在表中的分层数据的树表示。现在,我希望用户能够根据列对行进行排序。其中列为"计数"或"引用计数"。这些值基本上是整数。
实现本身是有效的,直到我引入QSortFilterProxyModel,并且我开始在视图中获得很多空行。困难的问题是,只有当我有很多行(比如几千行左右)时,这种情况才会发生。
实现排序代理的代码是:
rootItem = RBKit::SqlConnectionPool::getInstance()->rootOfSnapshot(snapShotVersion);
model = new RBKit::HeapDataModel(rootItem, this);
proxyModel = new SortObjectProxyModel(this);
proxyModel->setSourceModel(model);
ui->treeView->setModel(proxyModel);
ui->treeView->setSortingEnabled(true);
我已经对QSortFilterProxyModel类进行了子类化,子类实现非常简单:
https://gist.github.com/gnufied/115f1a4fae3538534511
文件上确实写着-
对于行为更复杂的源模型,可能需要重写这种简单的代理机制;例如,如果源模型提供了自定义的hasChildren()实现,则也应该在代理模型中提供一个
但除此之外,我不确定——我错过了什么。
所以,我想我已经找到了解决方案,修复似乎是在代理模型子类中重新实现fetchMore
,因为源模型报告的插入行与视图中实际存在行的位置不匹配(视图中的行由代理模型所有),所以这似乎为我修复了它:
#include "sortobjectproxymodel.h"
SortObjectProxyModel::SortObjectProxyModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
}
bool SortObjectProxyModel::hasChildren(const QModelIndex &parent) const
{
const QModelIndex sourceIndex = mapToSource(parent);
return sourceModel()->hasChildren(sourceIndex);
}
int SortObjectProxyModel::rowCount(const QModelIndex &parent) const
{
const QModelIndex sourceIndex = mapToSource(parent);
return sourceModel()->rowCount(sourceIndex);
}
bool SortObjectProxyModel::canFetchMore(const QModelIndex &parent) const
{
if(!parent.isValid())
return true;
else {
const QModelIndex sourceIndex = mapToSource(parent);
return sourceModel()->canFetchMore(sourceIndex);
}
}
void SortObjectProxyModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid() && parent.column() == 0) {
int row = parent.row();
int startRow = row + 1 ;
const QModelIndex sourceIndex = mapToSource(parent);
RBKit::HeapItem *item = static_cast<RBKit::HeapItem *>(sourceIndex.internalPointer());
if (!item->childrenFetched) {
qDebug() << "Insert New Rows at :" << startRow << " ending at : " << startRow + item->childrenCount();
beginInsertRows(parent, startRow, startRow + item->childrenCount());
item->fetchChildren();
endInsertRows();
}
}
}
感谢您的回复。在这一点上,我真的不在乎重新使用延迟加载的行(当节点被扩展时),所以我继续禁用了sortingEnabled
和dynamicSortFilter
。
新代码看起来像:
rootItem = RBKit::SqlConnectionPool::getInstance()->rootOfSnapshot(snapShotVersion);
model = new RBKit::HeapDataModel(rootItem, this);
proxyModel = new SortObjectProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->sort(2, Qt::DescendingOrder);
proxyModel->setDynamicSortFilter(false);
ui->treeView->setModel(proxyModel);
不过,这仍然留下了空行。
在我的oppinion中,您不需要为顶层的排序划分QSortFilterProxyModel
的子类。如果视图的sortingEnabled == true
,则视图将对代理模型执行排序,这是不可取的,因为模型应该对自己进行排序。您需要调用proxyModel->sort(desiredColumn)
,这将在视图中显示您的model
排序,而不会更改您的数据。默认情况下,QSortFilterProxyModel
启用其dynamicSortFilter
属性,这将导致代理模型在数据更改或插入或删除行时自动重新排序。我在HeapDataModel
中没有看到任何地方发出dataChanged信号,所以这可能是一个提示,可以让您获得动态排序的行。如果您需要对子项进行排序,那么它会稍微复杂一点,然后可能需要对QSortFilterProxyModel
进行子类化。这些模型视图抽象很难学习,但一旦你学会了,你就可以迅速创造奇迹。
rootItem = RBKit::SqlConnectionPool::getInstance()->rootOfSnapshot(snapShotVersion);
model = new RBKit::HeapDataModel(rootItem, this);
proxyModel = new SortObjectProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->sort(column);
ui->treeView->setModel(proxyModel);
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 如何使用用户输入在C++中正确填充2D数组
- 视图中的参数推导失败:take_while
- 如何找到大小'x'数组是否完全填充,在C++?
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 通过for循环使用用户输入填充列表
- 如何维护资源管理器项目视图中当前可见的项目列表
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 根据用户输入用字母填充矢量,并将"开始"和"结束"放在四肢
- 如何正确填充在堆上分配的二维数组?
- 将数字转换为填充字符串
- 有没有办法在一行中填充矢量图
- 用C++中的数字和条件填充向量
- 用真值填充矢量
- OpenVR:向视图方向移动
- 用来自 std::map 的数据填充 QML 列表视图
- 用驱动器上的目录和文件填充树视图
- 使用文档/视图分隔(MFC)填充组合框
- QSortFilterProxyModel和延迟填充的树视图