我为 QTreeView 创建了一个自定义模型。显示问题的完整最小代码如下。如果我向根节点添加一个新节点,通过单击“添加级别 1”,它就会显示。但是,如果我通过单击“添加级别 2”将新节点添加到第二级别,则它不会显示。仅当我折叠父节点然后再次展开它时,该节点才会显示。我的哪一部分MyTreeModel
出了问题?
我添加了 QT 标签,即使我的代码是 PySide6,因为错误可能在于我对 QAbstractItemModel 方法的理解,这不是 Python 或 PySide 特有的东西。
完整代码
from __future__ import annotations
from typing import Optional
from PySide6.QtCore import QAbstractItemModel, QModelIndex
from PySide6.QtGui import Qt
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QHBoxLayout, QTreeView
class TreeNode:
def __init__(self, name: str, parent_node):
self.name = name
self.parent_node = parent_node
self.children: list[TreeNode] = []
def get_child_by_name(self, name) -> Optional[TreeNode]:
for child in self.children:
if child.name == name:
return child
return None
class MyTreeModel(QAbstractItemModel):
def __init__(self):
super().__init__()
self.root_node = TreeNode("root", None)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return "Name"
def rowCount(self, parentIndex):
if not parentIndex.isValid():
parentNode = self.root_node
else:
parentNode = parentIndex.internalPointer()
return len(parentNode.children)
def columnCount(self, parent):
return 1
def data(self, index, role):
if not index.isValid():
return None
if role == Qt.DisplayRole:
node: TreeNode = index.internalPointer()
column = index.column()
match column:
case 0:
return node.name
case _:
return None
else:
return None
def parent(self, index):
if not index.isValid():
return QModelIndex()
childNode: TreeNode = index.internalPointer()
parentNode = childNode.parent_node
if parentNode == self.root_node:
return QModelIndex()
row_within_parent = parentNode.children.index(childNode)
return self.createIndex(row_within_parent, 0, parentNode);
def index(self, row, column, parentIndex):
if not self.hasIndex(row, column, parentIndex):
return QModelIndex()
if not parentIndex.isValid():
parentNode = self.root_node
else:
parentNode = parentIndex.internalPointer()
child_node = parentNode.children[row]
if child_node:
return self.createIndex(row, column, child_node)
else:
return QModelIndex()
def set_data(self, data: []):
self.beginResetModel()
self.apply_data(data)
self.endResetModel()
def update_data(self, data: []):
self.apply_data(data, True)
def apply_data(self, data, notify=False):
for item in data:
parent_node = self.root_node;
for part in item.split("/"):
existing = parent_node.get_child_by_name(part)
if existing:
parent_node = existing
else:
if notify:
parent_index = self.get_index(parent_node)
count = len(parent_node.children)
self.beginInsertRows(parent_index, count, count)
new_node = TreeNode(part, parent_node)
parent_node.children.append(new_node)
parent_node = new_node
if notify:
self.endInsertRows()
def get_index(self, node: TreeNode):
if not node.parent_node:
return QModelIndex()
row = node.parent_node.children.index(node)
return self.createIndex(row, 0, node.parent_node)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.resize(600, 400)
button1 = QPushButton("Add Level 1")
button1.clicked.connect(self.add1)
button2 = QPushButton("Add Level 2")
button2.clicked.connect(self.add2)
row1 = QHBoxLayout()
row1.setAlignment(Qt.AlignLeft)
row1.addWidget(button1)
row1.addWidget(button2)
self.tree_view = QTreeView()
layout = QVBoxLayout()
layout.addLayout(row1)
layout.addWidget(self.tree_view, stretch=1)
self.central_widget = QWidget()
self.central_widget.setLayout(layout)
self.setCentralWidget(self.central_widget)
def showEvent(self, event):
data = ["mammals", "birds", "mammals/dog", "birds/eagle", "mammals/cat"]
my_model = MyTreeModel()
my_model.set_data(data)
self.tree_view.setModel(my_model)
self.tree_view.expandAll()
def add1(self):
data = ["reptiles"]
m = self.tree_view.model()
m.update_data(data)
def add2(self):
data = ["mammals/rat"]
m = self.tree_view.model()
m.update_data(data)
app = QApplication([])
win = MainWindow()
win.show()
app.exec()