Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Crash sorting QTreeView using QSortFilterProxyModel
Forum Updated to NodeBB v4.3 + New Features

Crash sorting QTreeView using QSortFilterProxyModel

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 2.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Sriep
    wrote on last edited by
    #1

    Hi

    I have a QTreeView widget that I am has sorting implemented by clicking the headers. The sorting works ok, but the program after fiddling the program eventually crashes with

    FATAL: qabstractitemmodel.cpp:643 - ASSERT failure in QPersistentModelIndex::~QPersistentModelIndex: "persistent model indexes corrupted", file itemmodels\qabstractitemmodel.cpp, line 643

    A derived class
    class CredentialModelFilter : public QSortFilterProxyModel
    is used for the sorting. The less than function is

    /
    bool CredentialModelFilter::lessThan(const QModelIndex &srcLeft, const QModelIndex &srcRight) const
    {
        // Get src model
        CredentialModel *pSrcModel = dynamic_cast<CredentialModel *>(sourceModel());
    
        TreeItem *pLeftItem = pSrcModel->getItemByIndex(srcLeft);
        TreeItem *pRightItem = pSrcModel->getItemByIndex(srcRight);
    
        if ((pLeftItem != nullptr) && (pRightItem != nullptr))
            return pLeftItem->name() < pRightItem->name();
    
        return false;
    }
    

    Taking note of http://doc.qt.io/qt-5/model-view-programming.html I tried overriding the sort function like

    void CredentialModelFilter::sort(int column, Qt::SortOrder order)
    {
        emit layoutAboutToBeChanged();
        QModelIndexList oldPersistantIndexes = persistentIndexList();
    
        QSortFilterProxyModel::sort(column, order);
    
        QModelIndexList newPersistantIndexes = persistentIndexList();
        changePersistentIndexList(oldPersistantIndexes, newPersistantIndexes);
        emit layoutChanged();
    }
    

    Unfortunately, that did not make any difference, it still crashes on a subsequent click in the QTreeView.. I tried various other permutations to no effect.

    So any suggestions as to sort without messing everything up?

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      Unfortunately it looks like it's not a problem of sorting or of the proxy. CredentialModel is probably not implemented correctly. Subclassing QAbstractItemModel is a minefield and if you don't do it correctly a lot of stuff will stop working. In your case, the persistent model indexes do not update correctly when the model changes and they become corrupt.

      A good place to start is the model test. download modeltest.h and modeltest.cpp. When you create the source model (you have something like CredentialModel* myModel = new CredentialModel(this);) add a line with new ModelTest(myModel ,this); and use it as normal. it will assert if it detects something wrong

      P.S.
      My suggestion is always to use QStandardItemModel and switch to a custom model only if you have serious performance needs

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      S 1 Reply Last reply
      2
      • VRoninV VRonin

        Unfortunately it looks like it's not a problem of sorting or of the proxy. CredentialModel is probably not implemented correctly. Subclassing QAbstractItemModel is a minefield and if you don't do it correctly a lot of stuff will stop working. In your case, the persistent model indexes do not update correctly when the model changes and they become corrupt.

        A good place to start is the model test. download modeltest.h and modeltest.cpp. When you create the source model (you have something like CredentialModel* myModel = new CredentialModel(this);) add a line with new ModelTest(myModel ,this); and use it as normal. it will assert if it detects something wrong

        P.S.
        My suggestion is always to use QStandardItemModel and switch to a custom model only if you have serious performance needs

        S Offline
        S Offline
        Sriep
        wrote on last edited by
        #3

        @VRonin Thanks for your help.

        I looked at Model_Test. Some thoughts.
        The usage instructions were not very good. The .pri file mentioned was probably removed years ago.
        I followed the instructions about including modeltest.h in the code but with no result.
        The group of 6 files make an interesting test project. With dynamictreemodel.h/cpp being a custom QAbstractItemModel object to be tested. and tst_modeltest.cpp being a test script that you need to modify to fit your own model. So it needs a bit of work to get working, and the model I was working on passed all the tests.

        VRoninV 1 Reply Last reply
        0
        • S Offline
          S Offline
          Sriep
          wrote on last edited by Sriep
          #4

          The issue I have occurs in this bit of code bellow from QAbstractItemModelPrivate::removePersistentIndexData. The Q_ASSERT_X happens. This is during a mouse press and setCurrentIndex in the QTreeView.

          I put in some debug code that calls QAbstractItemModel::persistentIndexList and dumps the list to debug. I put this in the virtual CredentialModel::parent function. The only time any persistent indexes appear is during a sort, and they are removed by the time the sort function is exited.

          QItemSelectionModel::setCurrentIndex is called when clicking on the QTreeView GUI object. This function creates a QPeristentModelIndex called previous. The assert seems to happen when this object is deleted on leaving scope.

          void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
          {
          ...
              QPersistentModelIndex previous = d->currentIndex;
              d->currentIndex = index; // set current before emitting selection changed below
              if (command != NoUpdate)
                  select(d->currentIndex, command); // select item
              emit currentChanged(d->currentIndex, previous);
              if (d->currentIndex.row() != previous.row() ||
                      d->currentIndex.parent() != previous.parent())
                  emit currentRowChanged(d->currentIndex, previous);
              if (d->currentIndex.column() != previous.column() ||
                      d->currentIndex.parent() != previous.parent())
                  emit currentColumnChanged(d->currentIndex, previous);
          }
          

          This is the point of the assert

          void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexData *data)
          {
              if (data->index.isValid()) {
                  int removed = persistent.indexes.remove(data->index);
                  Q_ASSERT_X(removed == 1, "QPersistentModelIndex::~QPersistentModelIndex",
                             "persistent model indexes corrupted"); //maybe the index was somewhat invalid?
                  // This assert may happen if the model use changePersistentIndex in a way that could result on two
                  // QPersistentModelIndex pointing to the same index.
                  Q_UNUSED(removed);
              }
          ...
          }
          
          1 Reply Last reply
          0
          • S Sriep

            @VRonin Thanks for your help.

            I looked at Model_Test. Some thoughts.
            The usage instructions were not very good. The .pri file mentioned was probably removed years ago.
            I followed the instructions about including modeltest.h in the code but with no result.
            The group of 6 files make an interesting test project. With dynamictreemodel.h/cpp being a custom QAbstractItemModel object to be tested. and tst_modeltest.cpp being a test script that you need to modify to fit your own model. So it needs a bit of work to get working, and the model I was working on passed all the tests.

            VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by
            #5

            @Sriep said in Crash sorting QTreeView using QSortFilterProxyModel:

            The usage instructions were not very good.

            I know, that's why I included the usage instructions above

            download modeltest.h and modeltest.cpp [and add them to your project]. When you create the source model (you have something like CredentialModel* myModel = new CredentialModel(this);) add a line with new ModelTest(myModel ,this);

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            1 Reply Last reply
            2

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved