python - QTreeView 请求无效行的索引

标签 python pyqt mvp qtreeview qabstractitemmodel

看看下面的 MWE。

这是一个简单的QAbstractItemModel,只有一个级别,将其项目存储在列表中。我创建了一个 QTreeView 来显示模型,并创建了一个按钮来删除第二项。

from PyQt5.QtCore import QModelIndex, QAbstractItemModel, Qt
from PyQt5.QtWidgets import QTreeView, QApplication, QPushButton


class Item:
    def __init__(self, title):
        self.title = title


class TreeModel(QAbstractItemModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._items = []  # typing.List[Item]

    def addItem(self, item: Item):
        self.beginInsertRows(QModelIndex(), len(self._items), len(self._items))
        self._items.append(item)
        self.endInsertRows()

    def removeItem(self, item: Item):
        index = self._items.index(item)
        self.beginRemoveRows(QModelIndex(), index, index)
        self._items.remove(item)
        self.endRemoveRows()

    # ----- overridden methods from QAbstractItemModel -----

    # noinspection PyMethodOverriding
    def data(self, index: QModelIndex, role):
        item = index.internalPointer()
        if role == Qt.DisplayRole:
            return item.title

    # noinspection PyMethodOverriding
    def rowCount(self, parent=QModelIndex()):
        if not parent.isValid():
            return len(self._items)
        return 0

    # noinspection PyMethodOverriding
    def columnCount(self, parent=QModelIndex()):
        return 1

    # noinspection PyMethodOverriding
    def index(self, row: int, col: int, parent=QModelIndex()):
        assert not parent.isValid()
        return self.createIndex(row, 0, self._items[row])

    def parent(self, index=QModelIndex()):
        return QModelIndex()


def removeItem():
    model.removeItem(item2)


if __name__ == '__main__':
    app = QApplication([])
    model = TreeModel()
    button = QPushButton('Delete')
    button.clicked.connect(removeItem)
    button.show()
    item1 = Item('Item 1')
    model.addItem(item1)
    item2 = Item('Item 2')
    model.addItem(item2)
    treeView = QTreeView()
    treeView.setModel(model)
    treeView.show()

    app.exec()

据我所知,我的模型的实现是正确的(尽管非常基本)。特别是,它报告的行和列计数是正确的,并且它永远不会为无效的数据创建索引。

重现问题的步骤:

  • 运行上面的代码。
  • 在 TreeView 中,选择项目 2。
  • 删除按钮。

在我的系统上,应用程序在 beginRemoveRows() 中崩溃,因为 View 请求第 2 行的 QModelIndex。当然,第 2 行不存在。

知道为什么 QTreeView 会认为有 3 行,而模型明确报告只有 2 行?

最佳答案

当添加、移动、删除项目等时,模型所做的就是验证 QPersistentModelIndex 是否有效,因此它调用 index() QAbstractItemModel 的方法。在该方法中,开发人员有责任验证行或列是否有效,为此模型提供 hasIndex()您没有使用的方法导致了您指出的错误,因此解决方案是:

def index(self, row: int, col: int, parent=QModelIndex()):
    if not self.hasIndex(row, col, parent):
        return QModelIndex()
    assert not parent.isValid()
    return self.createIndex(row, 0, self._items[row])

关于python - QTreeView 请求无效行的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56261121/

相关文章:

python - 如何使用 PyQt5 在编辑器旁边打印文本

python - PyQt - 如果它已经在运行,如何检测和关闭 UI?

Python QTableWidget 不显示全宽

java - Android 中的 MVP 设计模式问题

android - Mosby MVP - 如何在 onDestroyView() 之后重新创建 Fragment 的状态?

python - Django 获取列表中每个值的最后一个对象

python - 使用多处理时实例属性不会持续存在

python - matplotlib FigureCanvasQTAgg : slow rotation and grid overlaping surface on QWidget

python - “dict”对象没有属性 'append'

user-interface - 在 MVP 界面模式中划分已经变得太大的演示者的好做法是什么?