【问题标题】:QTreeview iterating nodesQTreeview 迭代节点
【发布时间】:2020-07-16 04:37:52
【问题描述】:

我使用 PyQt5 和 QTreeview 来显示从文件加载的 xml 树(以及它的一些属性作为列)。这按预期工作。但我现在正在努力解决两件事:

  • itemChange 事件。树节点应该是可编辑的,我需要在编辑后做一些检查。 itemChange被调用,但在编辑一个节点时被调用了N次。
  • 从编辑的项目开始,我需要在树中上下移动并检查子节点和父节点。我希望这很简单,例如getParent() 用于一个方向,而递归getChildren() 用于另一个方向。但是如何从itemChange 事件QStandardItem 到父项和子项?
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_())

【问题讨论】:

    标签: python pyqt5 qtreeview


    【解决方案1】:

    回答第一个问题:每次调用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')
    

    【讨论】:

    • 正如你所说,很明显......我将信号添加到树而不是项目。谢谢你的帮助!!
    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-22
    • 2011-06-01
    • 1970-01-01
    相关资源
    最近更新 更多