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. Problem with QTreeView and QAbstractItemModel

Problem with QTreeView and QAbstractItemModel

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 267 Views 1 Watching
  • 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.
  • J Offline
    J Offline
    james b-s
    wrote last edited by
    #1

    Windows. Qt 5.15

    I have a QTreeView and QAbstractItemModel. When I remove rows from the model, it doesn't appear that things are properly updated. At some point, Qt calls parent() with a QModelIndex pointing to one of my objects that has been deleted. Calling isValid on the QModelIndex returns valid.

    I call begin/end remove rows

          beginRemoveRows(parentIndex, row, row);
          parentItem->RemoveChild(pItem);
          endRemoveRows();
    

    I even added an

      emit layoutChanged();
    

    for good measure.

    I added a call to persistentIndexList() in the parent method and discovered that the problem QModelIndex is in the list of persistent model indexes returned by persistentIndexList(). These aren't being created by me. The number of indexes returned is the same as the number of rows that I have in the tree. It appears that a persistent model index is created when I call QTreeView::expand. The item that I expand seems to be put into the persistent model list.

    I'm going to see what happens when I collapse the item before removing it, but it seems like I shouldn't have to do this. Everything I can find in the documentation says that persistent indexes are only created by user code, although the QT code seems to show otherwise.

    M 1 Reply Last reply
    0
    • J james b-s

      Windows. Qt 5.15

      I have a QTreeView and QAbstractItemModel. When I remove rows from the model, it doesn't appear that things are properly updated. At some point, Qt calls parent() with a QModelIndex pointing to one of my objects that has been deleted. Calling isValid on the QModelIndex returns valid.

      I call begin/end remove rows

            beginRemoveRows(parentIndex, row, row);
            parentItem->RemoveChild(pItem);
            endRemoveRows();
      

      I even added an

        emit layoutChanged();
      

      for good measure.

      I added a call to persistentIndexList() in the parent method and discovered that the problem QModelIndex is in the list of persistent model indexes returned by persistentIndexList(). These aren't being created by me. The number of indexes returned is the same as the number of rows that I have in the tree. It appears that a persistent model index is created when I call QTreeView::expand. The item that I expand seems to be put into the persistent model list.

      I'm going to see what happens when I collapse the item before removing it, but it seems like I shouldn't have to do this. Everything I can find in the documentation says that persistent indexes are only created by user code, although the QT code seems to show otherwise.

      M Offline
      M Offline
      Meghan1
      wrote last edited by Meghan1
      #2

      @james-b-s Hi James,

      It sounds like you’re running into the classic issue with persistent indexes in QAbstractItemModel. A common workaround is to temporarily collapse the item before removing it, as you mentioned. Another approach is to use utility tools for model debugging to track which indexes are still active and ensure they’re properly cleared before calling endRemoveRows().

      These tools can help visualize the model structure and persistent indexes, making it easier to identify why some indexes remain valid after removal.

      Hope this helps you debug the issue more efficiently!

      J 1 Reply Last reply
      0
      • M Meghan1

        @james-b-s Hi James,

        It sounds like you’re running into the classic issue with persistent indexes in QAbstractItemModel. A common workaround is to temporarily collapse the item before removing it, as you mentioned. Another approach is to use utility tools for model debugging to track which indexes are still active and ensure they’re properly cleared before calling endRemoveRows().

        These tools can help visualize the model structure and persistent indexes, making it easier to identify why some indexes remain valid after removal.

        Hope this helps you debug the issue more efficiently!

        J Offline
        J Offline
        james b-s
        wrote last edited by
        #3

        @Meghan1 That's what I was afraid of.

        Of course, I have to collapse not just the one that I am removing, but all of its children.

        1 Reply Last reply
        0
        • J james b-s has marked this topic as solved
        • J Offline
          J Offline
          james b-s
          wrote last edited by
          #4

          It appears that the problem is a bit more complicated that that. Collapsing things seem to work better, but there is still a problem. It also appears that selected items create persistent indexes, so I now make sure that items are both unselected and collapsed. Things work a bit better, but I'm still running into the same problem, just not as often.

          Right now, parent() is called with a QModelIndex that shouldn't be there, when Qt is trying to determine what is on the screen.

          1 Reply Last reply
          0
          • jeremy_kJ Offline
            jeremy_kJ Offline
            jeremy_k
            wrote last edited by jeremy_k
            #5

            Got a minimal working example?

            I'm not seeing a problem removing a row in an expanded tree, with a persistent index, testing with Qt 5.15.14 and 6.9.2.

            #include <QApplication>
            #include <QTreeView>
            #include <QStandardItemModel>
            #include <QStandardItem>
            #include <QTimer>
            #include <QPersistentModelIndex>
            #include <QDebug>
            
            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
                QTreeView view;
                QStandardItemModel model;
                QStandardItem *parentItem{new QStandardItem("parent")};
                QStandardItem *childItem{new QStandardItem("child")};
                parentItem->appendRow(childItem);
                model.appendRow(parentItem);
                view.setModel(&model);
                view.expandAll();
                view.setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
                view.selectAll();
            
                QPersistentModelIndex p{childItem->index()};
                qDebug() << p.isValid() << p.data();
                view.show();
                QTimer::singleShot(1000, [&]() { parentItem->removeRow(0); qDebug() << p.isValid(); });
                return app.exec();
            }
            

            QAbstractItemModelTester is worth a look.

            Asking a question about code? http://eel.is/iso-c++/testcase/

            1 Reply Last reply
            1
            • J Offline
              J Offline
              james b-s
              wrote last edited by
              #6

              It turns out I also have to reset the current index in the selection model.
              summary:

              1. Collapse row being removed and all descendant rows
              2. Unselect row being removed and all descendant rows (not sure this was necessary)
              3. Clear the current index for the selection model.
              1 Reply Last reply
              0
              • jeremy_kJ Offline
                jeremy_kJ Offline
                jeremy_k
                wrote last edited by
                #7

                Adding view.setCurrentIndex(childItem.index()) to the example posted above still doesn't exhibit the described behavior. The item and any children delegate instances are removed from the view without collapsing, deselecting, clearing the current index, or other mitigations.

                Does the example work as expected for you?

                Asking a question about code? http://eel.is/iso-c++/testcase/

                1 Reply Last reply
                0

                • Login

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