QTreeview 迭代节点

QTreeview iterating nodes

我使用 PyQt5 和 QTreeview 来显示从文件加载的 xml 树(及其一些属性作为列)。这按预期工作。但我现在正在为两件事而苦苦挣扎:

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

import xml.etree.ElementTree as ET

tree = ET.ElementTree(file='data.xml')


class MainFrame(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(MainFrame, self).__init__(parent)

        self.tree = QtWidgets.QTreeView(self)
        layout = QtWidgets.QHBoxLayout(self)
        layout.addWidget(self.tree)

        root_model = QtGui.QStandardItemModel()
        root_model.setHorizontalHeaderLabels(['Label', 'privilege', 'uid', 'docId'])
        self.tree.setModel(root_model)
        self.tree.setUniformRowHeights(True)
        root = tree.getroot()
        self._populateTree(root, root_model.invisibleRootItem())
        self.tree.expandAll()
        self.tree.resizeColumnToContents(0)
        self.tree.resizeColumnToContents(1)
        self.tree.resizeColumnToContents(2)
        self.move(0, 0)
        self.resize(800, 1000)
        #self.tree.itemChanged.connect(self.edit)


    def _populateTree(self, root, parent):
        child_item = QtGui.QStandardItem(root.tag)
        child_item.setData(root)

        privilege = ''
        uid = ''
        docId = ''
        privilege_item = QtGui.QStandardItem(privilege)
        uid_item = QtGui.QStandardItem(uid)
        docId_item = QtGui.QStandardItem(docId)

        parent.appendRow([child_item, privilege_item, uid_item, docId_item])
        privilege_item.model().itemChanged.connect(self.change_privilege)
        child_item.model().itemChanged.connect(self.change_privilege)

        for elem in root.getchildren():
            self._populateTree(elem, child_item)

    def change_privilege(self, item):
        print(item)
        print(item.row(), item.column())

    def check_parent(self, item):
        # get parent of item and check value
        # check_parent(...)

    def check_child(self, item):
        # get children of item and check value
        # for child in item.children():
        #     check_child(child)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main = MainFrame()
    main.show()
    sys.exit(app.exec_())

回答第一个问题:每次调用 MainFrame._populateTree 时,都会在信号 child_item.model().itemChangedprivilege_item.model().itemChanged 与槽 MainFrame.change_privilege 之间创建一个信号槽连接。但是,由于所有子项和特权项都属于同一模型(即 root_model),您实际上是在同一信号和插槽之间创建多个连接。这意味着当模型中的任何项目发生变化时,插槽也会被多次调用。解决此问题的最简单方法是在 __init__ 左右创建一个连接。

要访问项目的父项,您确实可以使用 item.parent()。可以通过 item.child(row, column) 逐一访问项目的子项,其中 rowrange(item.rowCount()) 范围内,columnrange(item.columnCount()) 范围内,例如

    def change_privilege(self, item):
        print(item.row(), item.column(), item.text())
        self.check_parent(item)
        self.check_child(item)


    def check_parent(self, item):
        if item.parent():
            print('Parent:', item.parent().text())
        else:
            print('No parent')

    def check_child(self, item):
        if item.hasChildren():
            print('Children:')
            for row in range(item.rowCount()):
                print('\t', row, end='')
                for col in range(item.columnCount()):
                    print('\t', item.child(row, col).text(), end='')
                print()
        else:
            print('No children')