删除最后一行的pyqt treeview索引错误

时间:2014-10-31 17:19:57

标签: python treeview pyqt delete-row qabstractitemmodel

我有一个2列树视图,简单的层次深度为2; root>父母>儿童。我在我的treeView子类中有一个removeRows调用,在按下删除键时会对其进行评估。当我删除任何行但最后一行时,这似乎工作正常。

我收到一个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

2 个答案:

答案 0 :(得分:4)

我花了一些时间,但我终于找到了错误的原因:根据index方法中的mail,您应该在继续之前检查索引是否存在。令人讨厌的是,它没有写在method description,也没有写在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()

在我的申请中,这解决了这个问题。

答案 1 :(得分:0)

对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)