Solved TreeView of QFileSystemModel: Remember selection after sorting
-
Hi,
I am trying to modify the filesystembrowser example (Qt-Creator -> Welcome -> Examples) to be able to sort by modification date. I did this via adding
Q_INVOKABLE virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override { qDebug("sort by column %d",column); QFileSystemModel::sort(column,order); }
to
DisplayFileSystemModel
and settingTreeView { sortIndicatorVisible: true
The sorting is working, but the selection will just stay at the same index. How should I do it so that the same file/s are still selected (I guess the indices change after the sorting)
-
Someone?
-
The problem seems to be that the selected indices in QItemSelectionModel do not get updated if I do a sorting of my model. But is there really no functionality in QT which takes care of this?
-
connect a slot to
QAbstractItemModel::layoutAboutToBeChanged
where you access theQItemSelectionModel::selection()
, iterate over all theindexes()
and save them in a list ofQPersistentModelIndexe
sThen create another slot to
QAbstractItemModel::layoutChanged
, clear the current selection, iterate over your saved indexes and re-select them -
@VRonin Thank you for your answer. I think you are right, this is probably how it should be done. Now I am wondering about the following: I store the persistent indices in a
QList<QPersistentModelIndex> _selectedIndices;
I set it via a Q_INVOKABLE function
Q_INVOKABLE void setSelected(QModelIndexList list) { _selectedIndices.clear(); for(int i=0;i<list.count();i++) { _selectedIndices.append(QPersistentModelIndex(list[i])); } }
Now I wonder about how to return it to QML so I don't get type problems
-
Ok, I should simply use a QVariantList instead of a QList<QPersistentModelIndex>. However, when I want to do the selection again in QML:
for(var item in selectionList) { selection.select(item); }
I get the following error:
qrc:/FileSystem.qml:136: Error: Unable to determine callable overload. Candidates are: select(QItemSelection,QItemSelectionModel::SelectionFlags) select(QModelIndex,QItemSelectionModel::SelectionFlags)
Why does it not recognice that the QVariant holds a QModelindex? But maybe I should do it all on the c++ side. However, I wonder how I get the QItemSelectionModel in my model, or how I can connect the QFileSystemModel and the QItemSelectionModel.
-
@maxwell31
Assuming QML compiler is no different than a prog lang compiler like C++, why should it? Each item in aQVariantList
is aQVariant
. They don't do code analysis :) You will need one of thecast<>
constructs, or similar, I presume. -
@JonB: Do you know how this can be done in QML? (I am calling the method from QML).
-
Hm, actually yes, I can use the conversion functions from QVariant.
Regarding my above error: The problem was I did not supply ItemSelectionModel.Select as the second argument
-
@VRonin : You suggested I should access
QItemSelectionModel
in c++, how can this be done, if theQItemSelectionModel
has only been attached to the view and not the model? -
@maxwell31 I was thinking of something like:
class SelectionSaver : public QObject Q_OBJECT Q_DISABLE_COPY(SelectionSaver) public: explicit SelectionSaver(QObject* parent = nullptr) : QObject(parent){} private: QVector<QPersistentModelIndex> m_indexList; public Q_SLOTS: void storeSelection(const QModelIndexList& sel){ m_indexList.clear(); m_indexList.reserve(sel.size()); for(auto&& idx : sel) m_indexList.append(idx); } void restoreSelection(QItemSelectionModel* selModel){ QItemSelection newSelection; for(auto&& idx : qAsConst(m_indexList)) newSelection.select(idx,idx); selModel->select(newSelection,QItemSelectionModel::ClearAndSelect); m_indexList.clear(); } };
Then from QML you call
storeSelection
passingTreeView.selection. selectedIndexes
and then callrestoreSelection
passingTreeView.selection
-
@VRonin Thanks a lot! I did not now that one can simply pass pointers of the objects from QML. However, for some reason it is not working yet. I will report on this tomorrow.
-
Yes, it works now. However, in
restoreSelection
you need to doselModel->clearSelection();
before
selModel->select
. Not sure why, but otherwise the new selection is not shown.