是什么触发 QTreeView 在 QAbstractItemModel.data() 函数中请求 SizeHintRole

what triggers a QTreeView to ask for a SizeHintRole in the QAbstractItemModel.data() function

我已经使用 TreeViewsAbstractItemModels 制作了一些不同的应用程序,但我遇到了一些我不明白的事情。我意识到该视图正在调用模型的 data 函数,为项目请求 Size,因为角色是 SizeHintRole (see Qt Documentation)。在所有其他情况下,我都不记得需要担心为 data 函数返回 size。在下面的代码中,我错误地认为 data 只会查找列表中的项目,如果您取消注释第一行,视图将不显示任何内容,因为实际上视图正在请求 sizeHint 的指数。

我的问题是,什么情况下需要这样做?我以前从来不需要提供 sizeHint,我不明白什么时候需要,什么时候不需要。

window当第一行被注释时

window当第一行启用时,因此忽略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()

默认为所有角色返回 self.root._items[index.row()] 毫无意义。您应该始终明确检查角色,并且只 return 一个适合 特定角色 的值。如果你没有特定于某个角色的数据,你应该在 PyQt 中 return None(相当于 C++ 中的无效 QVariant)。

有关基本要求的概述,请参阅 Model Subclassing Reference