QSortFilterProxyModel and lazily populated trees

I implemented a lazily populated tree by doing a subclass of QAbstractItemModel. The implementation looks something like this:

https://gist.github.com/gnufied/db9c4d805e2bb24d8c23

(I do not embed inline code to communicate with messages)

This is basically a tree view of hierarchical data stored in a table. Now I want users to be able to sort rows based on columns. Where the columns are: “count” or “reference count”. These values ​​are integers.

The implementation itself works until I type QSortFilterProxyModel and I start getting a lot of blank lines in the view. The tough problem is that this only happens when I have a lot of lines (like thousands or so).

Code for implementing a sorting proxy:

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); 

I have a QSortFilterProxyModel subclass class and the implementation of the subclass is very simple:

https://gist.github.com/gnufied/115f1a4fae3538534511

The documentation says -

"This simple proxy mechanism may need to be redefined for source models with more complex behavior, for example, if the source model provides a custom implementation of hasChildren (), you should also specify it in the proxy model."

But also, I’m not sure what I’m missing.

+5
source share
3 answers

So, I think I found a solution, and the fix seems to override fetchMore in the subclass of the proxy model, since the inserted rows represented by the original model do not coincide with the place where the rows actually exist (Rows in view are owned by the proxy model ), so this seems to fix this for me:

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

Thanks for answering. At this point, I really don't need to resort to lines that were lazily loaded (when the node was expanded), so I went ahead and disabled sortingEnabled and disabled dynamicSortFilter too.

The new code looks like this:

 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); 

However, this still leaves blank lines.

+2
source

In my solution, you do not need subclasses of QSortFilterProxyModel to sort on the top layer. If sortingEnabled == true for your view, then the view will sort by proxy model, which is undesirable since the model must sort itself. You need to call proxyModel->sort(desiredColumn) and display your model , sorted in the view, without changing your data. By default, QSortFilterProxyModel has the QSortFilterProxyModel property, which will cause the proxy model to be re-sorted automatically when inserting or deleting data. I have not seen the emitted dataChanged signal anywhere in your HeapDataModel , so maybe this could be a hint for getting dynamically sorted strings. If you need to sort the subelements, then it will be a little more complicated, and then you may need to subclass QSortFilterProxyModel . These abstract abstractions of the model are hard to recognize, but once you get it, you can quickly perform miracles.

 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); 
+1
source

Source: https://habr.com/ru/post/1202110/


All Articles