QSortFilterProxyModel和延迟填充的树视图

时间:2014-09-08 22:22:28

标签: c++ qt

我通过继承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()实现,则还应在代理模型中提供一个。”

但除此之外,我不确定 - 我错过了什么。

3 个答案:

答案 0 :(得分:4)

所以,我认为我找到了解决方案并且修复似乎是在代理模型子类中重新实现fetchMore,因为源模型报告的插入行与视图中实际存在行的位置不匹配(Rows in视图由代理模型拥有),所以这似乎已经为我修复了它:

#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();
        }
    }
}

答案 1 :(得分:2)

感谢您的回复。在这一点上,我真的不关心延迟加载的行(当节点被扩展时),所以我继续禁用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);

但仍然留有空行。

答案 2 :(得分:1)

在我的意见中你不需要将QSortFilterProxyModel子类化为顶层的排序。如果您的视图为sortingEnabled == true,则视图将对代理模型执行排序,这是不可取的,因为模型应对自身进行排序。您需要的是致电proxyModel->sort(desiredColumn),这将显示您在视图中排序的model,而不会更改您的数据。默认情况下,QSortFilterProxyModel的{​​{1}}属性处于打开状态,这将导致代理模型在数据更改或插入或删除行时自动重新排序。我没有在dynamicSortFilter的任何地方看到发出dataChanged信号,所以也许这可能是你获得动态排序行的提示。如果你需要对子项进行排序,那么它就会变得更加复杂,然后你可能需要子类HeapDataModel。这些模型 - 视图抽象很难学习,但一旦你得到它,你就可以迅速创造奇迹。

QSortFilterProxyModel