gpt4 book ai didi

python - 如何在具有不同层次列数的模型的 QTreeView 中显示正确的列数

转载 作者:行者123 更新时间:2023-12-05 04:03:50 25 4
gpt4 key购买 nike

在下面的代码示例中,我使用一组顶级项目填充项目模型,这些项目包含我可以使用 QTreeView 查看和编辑的键值属性。

查看 QAbstractItemModel::columnCount 的 Qt 文档它说这应该返回给定父级的子级的列数,这意味着这应该是一个层次相关的属性。

但是,使用下面的代码,如果我将列计数作为分层相关属性返回(在这种情况下,root->children 有 1 列,root->child->children 有 2 列)那么 View 将只显示 1 列。

enter image description here

打印 node.columnCount()(参见代码)实际上会显示 Item 类节点在展开其中一项后实际上会返回 columnCount = 2 .

如果我总是为 model.columnCount 函数返回 2,那么 View 将正确显示两列。

enter image description here

无论层次结构如何,这是否需要始终返回 View 中所需的列数,或者我只是做错了什么,如果是这样怎么办?为父级返回多个列,而父级的子级具有不同的列数,只是为了使 View 正常工作,这感觉一定是错误的。

import sys
import typing
from PyQt5 import QtCore, QtWidgets


class Node:
def __init__(self, parent=None):
self.parent = parent # type: Node
self.name : str

def children(self) -> list:
return None

def hasChildren(self):
return bool(self.children())

def getData(self, index: QtCore.QModelIndex):
if index.column() == 0:
return self.name

def setData(self, val, index: QtCore.QModelIndex):
if index.column() == 0:
self.name = val

def columnCount(self):
return 1

def rowCount(self):
children = self.children()
return 0 if not children else len(children)

def flags(self, index: QtCore.QModelIndex):
if index.column() == 0:
return (QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable)
else:
return QtCore.Qt.NoItemFlags


class Property(Node):
def __init__(self, parent, label, value):
super().__init__(parent)
self.label = label
self.value = value

def getData(self, index: QtCore.QModelIndex):
col = index.column()
if col == 0:
return self.label
elif col == 1:
return self.value

def setData(self, val, index: QtCore.QModelIndex):
if index.column() == 1:
self.value = val

def flags(self, index: QtCore.QModelIndex):
col = index.column()
if col == 0:
return QtCore.Qt.ItemIsEnabled
elif col == 1:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEditable


class Item(Node):
def __init__(self, parent):
super().__init__(parent)
self.name = 'Item'
self.p1 = Property(self, 'string', 'text')
self.p2 = Property(self, 'float', 1.2)

def children(self):
return [self.p1, self.p2]

def columnCount(self):
return 2


class Root(Node):
def __init__(self):
super().__init__(parent=None)
self._children = list()

def children(self):
return self._children


class Model(QtCore.QAbstractItemModel):
def __init__(self):
super().__init__()
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()

node = parent.internalPointer() if parent.isValid() else self.root
if node.children:
return self.createIndex(row, column, node.children()[row])
else:
return QtCore.QModelIndex()

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

node = child.internalPointer() # type: Node

if node.parent and node.parent.parent:
row = node.parent.parent.children().index(node.parent)
return self.createIndex(row, 0, node.parent)
else:
return QtCore.QModelIndex()

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

def columnCount(self, parent: QtCore.QModelIndex = ...) -> int:
node = parent.internalPointer() if parent.isValid() else self.root
print(f'{node.__class__.__name__} column count: ', node.columnCount()) # shows that column count 2 is returned, when items are expanded
# return 2 # 2nd column only shows up if I just always return 2
return node.columnCount() # view only shows 1 columns

def hasChildren(self, parent: QtCore.QModelIndex = ...) -> bool:
node = parent.internalPointer() if parent.isValid() else self.root
return node.hasChildren()

def data(self, index: QtCore.QModelIndex, role: int = ...):
if index.isValid() and role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
node = index.internalPointer() # type: Node
return node.getData(index)
else:
return None

def setData(self, index: QtCore.QModelIndex, value: typing.Any, role: int = ...) -> bool:
if role in (QtCore.Qt.EditRole,):
node = index.internalPointer() # type: Node
node.setData(value, index)
self.dataChanged.emit(index, index)
return True
else:
return False

def flags(self, index: QtCore.QModelIndex):
node = index.internalPointer() if index.isValid() else self.root
return node.flags(index)

def appendRow(self, item):
row = len(self.root.children())
self.beginInsertRows(QtCore.QModelIndex(), row, row)
self.root.children().append(item)
self.endInsertRows()


class TreeView(QtWidgets.QTreeView):
def __init__(self, parent=None):
super(TreeView, self).__init__(parent)
self._model = Model()
self.setModel(self._model)
self.setSelectionMode(self.ExtendedSelection)
# self.setDropIndicatorShown(False)
self.setEditTriggers(self.DoubleClicked | self.SelectedClicked | self.EditKeyPressed)

def model(self) -> Model:
return self._model

sys.excepthook = sys.__excepthook__
app = QtWidgets.QApplication(sys.argv)
widget = TreeView()
model = widget.model()
for i in range(2):
model.appendRow(Item(model.root))
widget.show()
widget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
sys.exit(app.exec_())

最佳答案

文档似乎不明确且与实现不完全匹配,在实现中 View 中的列数取决于水平QHeaderView,以及水平QHeaderView 使用作为不可见项的根的列数,即列数应由 Root() 给出。 , 自 Root()不会覆盖 columnCount()默认情况下它的值为 1(尽管对我来说 Node 的 columnCount() 必须为 0 而 children() 必须返回一个空列表),所以解决方案在 Root columnCount() 中设置为 2 .

import sys
import typing
from PyQt5 import QtCore, QtWidgets


class Node:
def __init__(self, parent=None):
self.parent = parent # type: Node
self.name : str

def children(self) -> list:
return list()

def hasChildren(self):
return bool(self.children())

def getData(self, index: QtCore.QModelIndex):
if index.column() == 0:
return self.name

def setData(self, val, index: QtCore.QModelIndex):
if index.column() == 0:
self.name = val

def columnCount(self):
return 0

def rowCount(self):
children = self.children()
return len(children)

def flags(self, index: QtCore.QModelIndex):
if index.column() == 0:
return (QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable)
else:
return QtCore.Qt.NoItemFlags


class Property(Node):
def __init__(self, parent, label, value):
super().__init__(parent)
self.label = label
self.value = value

def getData(self, index: QtCore.QModelIndex):
col = index.column()
if col == 0:
return self.label
elif col == 1:
return self.value

def setData(self, val, index: QtCore.QModelIndex):
if index.column() == 1:
self.value = val

def flags(self, index: QtCore.QModelIndex):
col = index.column()
if col == 0:
return QtCore.Qt.ItemIsEnabled
elif col == 1:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEditable

def columnCount(self):
return 1


class Item(Node):
def __init__(self, parent):
super().__init__(parent)
self.name = 'Item'
self.p1 = Property(self, 'string', 'text')
self.p2 = Property(self, 'float', 1.2)

def children(self):
return [self.p1, self.p2]

def columnCount(self):
return 2


class Root(Node):
def __init__(self):
super().__init__(parent=None)
self._children = list()

def children(self):
return self._children

def columnCount(self):
return 2


class Model(QtCore.QAbstractItemModel):
def __init__(self):
super().__init__()
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()

node = parent.internalPointer() if parent.isValid() else self.root
if node.children:
return self.createIndex(row, column, node.children()[row])
else:
return QtCore.QModelIndex()

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

node = child.internalPointer() # type: Node

if node.parent and node.parent.parent:
row = node.parent.parent.children().index(node.parent)
return self.createIndex(row, 0, node.parent)
else:
return QtCore.QModelIndex()

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

def columnCount(self, parent: QtCore.QModelIndex = ...) -> int:
node = parent.internalPointer() if parent.isValid() else self.root
print(f'{node.__class__.__name__} column count: ', node.columnCount()) # shows that column count 2 is returned, when items are expanded
# return 2 # 2nd column only shows up if I just always return 2
return node.columnCount() # view only shows 1 columns

def hasChildren(self, parent: QtCore.QModelIndex = ...) -> bool:
node = parent.internalPointer() if parent.isValid() else self.root
return node.hasChildren()

def data(self, index: QtCore.QModelIndex, role: int = ...):
if index.isValid() and role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
node = index.internalPointer() # type: Node
return node.getData(index)
else:
return None

def setData(self, index: QtCore.QModelIndex, value: typing.Any, role: int = ...) -> bool:
if role in (QtCore.Qt.EditRole,):
node = index.internalPointer() # type: Node
node.setData(value, index)
self.dataChanged.emit(index, index)
return True
else:
return False

def flags(self, index: QtCore.QModelIndex):
node = index.internalPointer() if index.isValid() else self.root
return node.flags(index)

def appendRow(self, item):
row = len(self.root.children())
self.beginInsertRows(QtCore.QModelIndex(), row, row)
self.root.children().append(item)
self.endInsertRows()


class TreeView(QtWidgets.QTreeView):
def __init__(self, parent=None):
super(TreeView, self).__init__(parent)
self._model = Model()
self.setModel(self._model)
self.setSelectionMode(self.ExtendedSelection)
# self.setDropIndicatorShown(False)
self.setEditTriggers(self.DoubleClicked | self.SelectedClicked | self.EditKeyPressed)

def model(self) -> Model:
return self._model

sys.excepthook = sys.__excepthook__
app = QtWidgets.QApplication(sys.argv)
widget = TreeView()
model = widget.model()
for i in range(2):
model.appendRow(Item(model.root))
widget.show()
widget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
sys.exit(app.exec_())

关于python - 如何在具有不同层次列数的模型的 QTreeView 中显示正确的列数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53219850/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com