Ошибка индекса дерева pyqt при удалении последней строки

У меня есть 2 столбца treeView с простой глубиной иерархии 2; корень > родитель > ребенок. У меня есть вызов removeRows в моем подклассе treeView, который оценивается при нажатии клавиши удаления. Кажется, это работает нормально, когда я удаляю любую строку, кроме последней.

Я получаю IndexError: list index out of range, который, кажется, исходит от метода child класса узла. Кажется, это происходит, когда метод self.beginRemoveRows вызывается в модели removeRows. Как ни странно, порядок операций кажется обратным, или потоки каким-то образом вызывают обновление до того, как модель узнает о своем недавнем обновлении.

С помощью этих фрагментов кода я надеялся, что кто-нибудь сможет дать возможное объяснение или некоторые идеи о том, что попробовать дальше, чтобы отладить это.

из подкласса QTreeView,

def keyPressEvent(self, event):
    if event.key() == Qt.Key_Delete:
        index = self.currentIndex()
        self.model().removeRow(index.row())
    else:
        # call base class keyPressEvent
        QTreeView.keyPressEvent(self, event)  

из подкласса QAbstractItemModel,

def index(self, row, column, parent=QModelIndex()):
    parent_node = self.getNode(parent)
    child_item = parent_node.child(row)
    if child_item:
        return self.createIndex(row, column, child_item)
    else:
        return QModelIndex()

def getNode(self, index):
    if index.isValid():
        node = index.internalPointer()
        if node:
            return node
    return self._root

def removeRows(self, position, rows, parent=QModelIndex()):

    parent_node = self.getNode(parent)
    self.beginRemoveRows(parent, position, position + rows - 1)
    parent_node.removeChild(position)
    self.endRemoveRows()
    return True

из класса узла,

def child(self, row):
    return self._children[row]

def removeChild(self, position):

    if position < 0 or position >= len(self._children):
        return False

    child = self._children.pop(position)
    child._parent = None

    return True

person tom voll    schedule 31.10.2014    source источник
comment
Я думаю, что решил эту проблему, очистив выбор перед удалением последнего индекса. TreeView пытался выбрать что-то еще, так как выбранный индекс удалялся, и он не обновлял rowCount перед обновлением... Я полагаю, это может быть ошибка?   -  person tom voll    schedule 17.11.2014
comment
Как ты сделал это? Я пытаюсь сделать то же самое безрезультатно. Если вы решили свой вопрос, вы можете ответить с решением и принять свой собственный ответ.   -  person Francesco Montesano    schedule 14.09.2015


Ответы (2)


Мне потребовалось некоторое время, но я, наконец, нашел причину ошибки: согласно этому mail в методе index вы должны проверить, существует ли индекс, прежде чем продолжить. К сожалению, это не написано ни в описании метода, ни в документации qt4 или qt5. .

Правильная реализация метода index должна быть примерно такой:

def index(self, row, column, parent=QModelIndex()):
    if self.hasIndex(row, column, parentIndex):
        parent_node = self.getNode(parent) 
        child_item = parent_node.child(row)
        if child_item:
            return self.createIndex(row, column, child_item)
    else:
        return QModelIndex()

В моем приложении это решило проблему.

person Francesco Montesano    schedule 16.09.2015
comment
Не уверен, что кто-то смотрит или увидит это, но просто хотел опубликовать, что я только что нашел это, и это спасло мою задницу. У меня была такая же проблема, и это решило ее для меня. - person jfsturtz; 25.04.2019

Это изменение в QTreeView, похоже, помогло. Хотя я не совсем уверен, что проблема не была вызвана чем-то другим.

def keyPressEvent(self, event):
    if event.key() == Qt.Key_Delete:
        index = self.currentIndex()
        if not index.isValid(): return

        parent = index.parent()

        # adjust selection so refresh does not trigger IndexError 
        self.selectionModel().setCurrentIndex(self.indexAbove(index), QItemSelectionModel.ClearAndSelect)

        # remove selected
        self.model().removeRow(row, parent=parent)

        return

    # call base class keyPressEvent
    QTreeView.keyPressEvent(self, event)
person tom voll    schedule 15.09.2015