что заставляет QTreeView запрашивать SizeHintRole в функции QAbstractItemModel.data()

Я сделал несколько разных приложений, используя TreeViews и AbstractItemModels, но столкнулся с чем-то, чего не понимаю. Я понял, что представление вызывало функцию data модели, запрашивающую Size для элементов, поскольку роль была SizeHintRole (см. документацию Qt). Во всех остальных случаях я не помню, чтобы мне приходилось беспокоиться о возврате size для функции data. В приведенном ниже коде я ошибочно ожидал, что data будет просто искать элементы в списке, и если вы раскомментируете первую строку, представление ничего не отобразит, потому что на самом деле представление запрашивает sizeHint индексов.

У меня вопрос, какие обстоятельства требуют этого? Мне никогда раньше не приходилось предоставлять sizeHint, и я не понимаю, когда это требуется, а когда нет.

окно, когда первая строка закомментирована

введите здесь описание изображения

окно, когда первая строка включена, поэтому игнорируйте запрос sizeHint

введите здесь описание изображения

import sys
from PyQt5 import QtCore, QtWidgets

class TreeList:
    def __init__(self):
        self._items = list()

class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self, root, parent=None):
        super().__init__(parent)
        self.root = root

    def index(self, row: int, column: int, parent: QtCore.QModelIndex = ...) -> QtCore.QModelIndex:
        if not self.hasIndex(row, column, parent):
            return QtCore.QModelIndex()

        if not parent.isValid():
            pointer = self.root  # type: TreeList
            child = pointer._items[row]
        else:
            child = None

        return self.createIndex(row, column, child)

    def addItem(self, layer):
        row = len(self.root._items)
        self.beginInsertRows(QtCore.QModelIndex(), row, row)
        self.root._items.append(layer)
        self.endInsertRows()

    def parent(self, child: QtCore.QModelIndex) -> QtCore.QModelIndex:
        return QtCore.QModelIndex()

    def rowCount(self, parent: QtCore.QModelIndex = ...) -> int:
        if parent.isValid():
            return 0
        else:
            return len(self.root._items)

    def columnCount(self, parent: QtCore.QModelIndex = ...) -> int:
        return 1

    def hasChildren(self, parent: QtCore.QModelIndex = ...) -> bool:
        return False if parent.isValid() else True

    def data(self, index: QtCore.QModelIndex, role: int = ...):
        # return self.root._items[index.row()]
        if role == QtCore.Qt.SizeHintRole:
            print(index.isValid(), index.row(), index.column())
            return QtCore.QSize(100, 20)
        else:
            return self.root._items[index.row()]

    def flags(self, index: QtCore.QModelIndex):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable


class StackTreeView(QtWidgets.QTreeView):
    def __init__(self, data=None, parent=None):
        super().__init__(parent)
        self.setModel(TreeModel(data))

    def addItem(self, layer):
        self.model().addItem(layer)


def test():
    app = QtWidgets.QApplication(sys.argv)
    data = TreeList()
    data._items = ['one', 'two']
    sys.excepthook = sys.__excepthook__
    tree_view = StackTreeView(data)
    tree_view.show()
    tree_view.addItem('three')
    tree_view.addItem('four')
    sys.exit(app.exec_())


if __name__ == '__main__':
    test()

person Vince W.    schedule 01.11.2018    source источник


Ответы (1)


Возврат self.root._items[index.row()] по умолчанию для всех ролей вообще не имеет смысла. Вы всегда должны явно проверять роль и возвращать только значение, подходящее для этой конкретной роли. Если у вас нет данных, относящихся к роли, вы должны вернуть None в PyQt (что эквивалентно недопустимому QVariant в C++).

См. Справочник по созданию подклассов модели. описание основных требований.

person ekhumoro    schedule 01.11.2018