QTreeView запрашивает индекс для неверной строки - PullRequest
2 голосов
/ 22 мая 2019

Взгляните на следующие MWE.

Это простой QAbstractItemModel только с одним уровнем, хранящий свои элементы в списке.Я создаю QTreeView для отображения модели и кнопку для удаления 2-го элемента.

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

Насколько я могу судить, реализация моей модели правильная (хотя и очень базовая).В частности, счетчики строк и столбцов, которые он сообщает, являются правильными, и он никогда не создает индексы для данных, которые были бы недействительными.

Шаги для воспроизведения моей проблемы:

  • Запустите кодвыше.
  • В древовидном представлении выберите Элемент 2.
  • Нажмите кнопку Удалить .

В моей системе происходит сбой приложенияв beginRemoveRows(), потому что представление запрашивает QModelIndex для строки 2. Естественно, строка 2. не существует.

Любая идея, почему QTreeView будет думать, что будет 3 строки, когдамодель явно сообщает, что есть только 2?

1 Ответ

1 голос
/ 22 мая 2019

Когда элемент добавляется, перемещается, удаляется и т. Д., Модель проверяет, является ли 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])
...