Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 setting

    TreeView {
        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 the QItemSelectionModel::selection(), iterate over all the indexes() and save them in a list of QPersistentModelIndexes

    Then 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 a QVariantList is a QVariant. They don't do code analysis :) You will need one of the cast<> 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 the QItemSelectionModel 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 passing TreeView.selection. selectedIndexes and then call restoreSelection passing TreeView.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 do

              selModel->clearSelection();
    

    before selModel->select. Not sure why, but otherwise the new selection is not shown.


Log in to reply