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. QAbstractItemModel + QSortFilterProxyModel : removing rows does not work

QAbstractItemModel + QSortFilterProxyModel : removing rows does not work

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 4 Posters 6.6k 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.
  • E Offline
    E Offline
    elveatles
    wrote on last edited by
    #1

    I'm using PySide, but the issue I'm having might be the same with plain Qt.
    I'm getting bugs when I try to remove rows from a QAbstractItemModel when I use a QSortFilterProxyModel with it. If I don't use the QSortFilterProxyModel, it works as expected.

    Here it is before removing the rows:
    alt text

    Here's what it's supposed to look like (no children). I'm not using a QSortFilterProxyModel in this one:
    alt text

    Here's what happens when I use a QSortFilterProxyModel (the white part is a selected row):
    alt text

    Here is a simplified version of my code:

    self._treeView = QTreeView()
    self._customModel = CustomModel()
    self._proxyModel = QSortFilterProxyModel()
    self._proxyModel.setSourceModel(self._customModel)
    self._treeView.setModel(self._proxyModel)
    

    I'm completely stumped why it's like this. I'd really appreciate any help.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What do you mean by remove row ? When it's filtered or when you delete it from your model ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • E Offline
        E Offline
        elveatles
        wrote on last edited by
        #3

        I'm actually deleting the rows from my model by using beginRemoveRows(), then removing all of the parent item's children, then calling endRemoveRows().

        1 Reply Last reply
        0
        • OrkbluttO Offline
          OrkbluttO Offline
          Orkblutt
          wrote on last edited by
          #4

          Hi,

          are you getting the QModelIndex from your proxy model or from your QAIM's model? If you're using your QAIM's model, you should get the index using mapFromSource:

          void removeRow(const QModelIndex& parent)
          {
          QModelIndex index =  _yourProxyModel->mapFromSource(parent);
          beginRemoveRows(index,....);
          // do you cleaning 
          endRemoveRows();
          }
          

          hope it helps

          1 Reply Last reply
          0
          • E Offline
            E Offline
            elveatles
            wrote on last edited by
            #5

            I'm using the index from my source model. In setData, if the version is changed, then it removes all children, then adds the new children for that version.
            In the example below, I'm just removing children because I want to get that working before I add the new children.

            def setData(self, index, value, role=Qt.EditRole):
                    if not index.isValid():
                        return False
                    
                    if role == Qt.EditRole:
                        if index.column() == versionColumn:
                            item = index.internalPointer()
                            last = self.rowCount(index) - 1
                            self.beginRemoveRows(index, 0, last)
                            item._children = []
                            self.endRemoveRows()
                            return True
                    
                    return False
            
            1 Reply Last reply
            0
            • OrkbluttO Offline
              OrkbluttO Offline
              Orkblutt
              wrote on last edited by
              #6

              try to map the index to your proxymodel as I said...I'm pretty sure the magie will come here.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                There's something strange with your logic here: why does doing any change to the versionColumn trigger that delete ? Also is _children really related to the model itself in terms of indexes ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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

                  instead of doing it manually with

                      self.beginRemoveRows(index, 0, last)
                      item._children = []
                      self.endRemoveRows()
                  

                  try using removeRows() if that works.

                  On a separate note I'm not sure inserting/deleting rows in the setData method is such a good design

                  "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
                  0
                  • E Offline
                    E Offline
                    elveatles
                    wrote on last edited by elveatles
                    #9

                    I was able to remove rows using everyone's suggestions.

                    I implemented the removeRows method:

                    def removeRows(self, row, count, parent=QModelIndex()):
                            last = row + count - 1
                            self.beginRemoveRows(parent, row, last)
                            item = parent.internalPointer()
                            item.removeRows(row, count)
                            self.endRemoveRows()
                    

                    I emit the dataChanged signal in setData:

                    def setData(self, index, value, role=Qt.EditRole):
                            if not index.isValid():
                                return False
                            
                            item = index.internalPointer()
                            
                            if role == Qt.EditRole:
                                if index.column() == versionColumn:
                                    item.currentVersion = value
                                    self.dataChanged.emit(index, index)
                                    return True
                            
                            return False
                    

                    I connect to the dataChanged signal of the QSortFilterProxyModel. By calling removeRows from the QSortFilterProxyModel instead of inside the QAbstractItemModel, it seems to have fixed the issue:

                    @Slot(QModelIndex, QModelIndex)
                    def onVersionDataChanged(self, topLeft, bottomRight):
                        if topLeft.column() == versionColumn:
                            count = self._versionSortFilterProxyModel.rowCount(topLeft)
                            self._versionSortFilterProxyModel.removeRows(0, count, topLeft)
                    

                    However, using insertRows does not work properly now. Right after remove rows I do this:

                    sourceIndex = self._versionSortFilterProxyModel.mapToSource(topLeft)
                    item = sourceIndex.internalPointer()
                    self._versionSortFilterProxyModel.insertRows(0, item.childrenToCreate, topLeft)
                    
                    def insertRows(self, row, count, parent=QModelIndex()):
                        last = row + count - 1
                        self.beginInsertRows(parent, row, last)
                        item = parent.internalPointer()
                        item.createChildren()
                        self.endInsertRows()
                        return True
                    

                    Here's what it looks like:
                    alt text

                    It started with 4 rows, I removed all of them, then I inserted 3 rows. Yet there are still 4 (the fourth one is blank).

                    What I was really hoping for was begineResetModel()/endResetModel() but for 1 row instead. However, there is nothing like this which is why I'm using remove then insert.

                    @SGaist
                    Changing the version needs to change the children, because the children represent the contents of that version. A different version will contain different contents which is why I'm removing then inserting after a version is set.

                    1 Reply Last reply
                    0
                    • E Offline
                      E Offline
                      elveatles
                      wrote on last edited by
                      #10

                      I found a solution which is not ideal, but it was the only thing that really worked.
                      I put my code back to the way it was before and instead of using removeRows and insertRows for an item, I emit layoutAboutToBeChanged, then I change the version and the item's children, then I emit layoutChanged.

                      The reason this is not ideal is because the whole view gets updated instead of just the item and its children. I'm sure this means that every item gets sorted and filtered again. It seems that this has changed with Qt 5.x, but unfortunately PySide does not support Qt 5.x.

                      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