递归地收集 QTreeview 中的所有项目

collect all items in QTreeview recursively

我如何收集所有 Qtreeview 项目以便我可以迭代它们并应用必要的更改,如显示文本更新或颜色更改?

有没有一种简单的方法可以使用 'match' 方法收集所有这些?

def get_checked(self):
    model = self.treeview.model()
    checked = model.match(
        model.index(0, 0), QtCore.Qt.CheckStateRole,
        QtCore.Qt.Checked, -1,
        QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
    for index in checked:
        item = model.itemFromIndex(index)
        print(item.text())

测试代码:

from PySide import QtGui, QtCore
from PySide import QtSvg, QtXml
import sys

class Person:
    def __init__(self, name="", children=None):
        self.name = name
        self.children = children if children else []

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.resize(300, 400)
        self.init_ui()

    def init_ui(self):
        # Setup Tabs Widget
        # self.treeview = QtGui.QTreeView()
        self.treeview = QtGui.QTreeView()
        self.treeview.setHeaderHidden(True)
        self.treeview.setUniformRowHeights(True)
        self.treeview.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)

        self.model = QtGui.QStandardItemModel()
        self.treeview.setModel(self.model)

        self.action = QtGui.QAction('Print', self)
        self.action.setShortcut('F5')
        self.action.triggered.connect(self.get_checked)

        fileMenu = QtGui.QMenu("&File", self)
        fileMenu.addAction(self.action)
        self.menuBar().addMenu(fileMenu)

        # Setup central widget
        self.setCentralWidget(self.treeview)

        # populate data
        self.populate_people()
        self.treeview.expandAll()

    def populate_people(self):
        parent = Person("Kevin", [
                Person("Tom", [Person("Sally"), Person("Susan")]),
                Person("Snappy", [Person("John"), Person("Kimmy"),
                                  Person("Joe")]),
                Person("Chester", [Person("Danny"), Person("Colleen")])
            ]
        )
        self.create_nodes(parent, self.model)

    def create_nodes(self, node, parent):
        tnode = QtGui.QStandardItem()
        tnode.setCheckable(True)
        tnode.setData(QtCore.Qt.Unchecked, role=QtCore.Qt.CheckStateRole)
        tnode.setData(node.name , role=QtCore.Qt.DisplayRole)
        tnode.setData(node, role=QtCore.Qt.UserRole) # store object on item

        parent.appendRow(tnode)

        for x in node.children:
            self.create_nodes(x, tnode)

    def get_checked(self):
        print "collecting..."


def main():
    app = QtGui.QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

这是一个递归的解决方案(要求Python >= 3.3):

def iterItems(self, root):
    def recurse(parent):
        for row in range(parent.rowCount()):
            for column in range(parent.columnCount()):
                child = parent.child(row, column)
                yield child
                if child.hasChildren():
                    yield from recurse(child)
    if root is not None:
        yield from recurse(root)

替代递归解决方案(对于Python2/Python3):

def iterItems(self, root):
    def recurse(parent):
        if root is not None:
            for row in range(parent.rowCount()):
                for column in range(parent.columnCount()):
                    child = parent.child(row, column)
                    yield child
                    if child.hasChildren():
                        for item in recurse(child):
                            yield item
    return recurse(root)

这是一个迭代解决方案(Python2/Python3):

def iterItems(self, root):
    if root is not None:
        stack = [root]
        while stack:
            parent = stack.pop(0)
            for row in range(parent.rowCount()):
                for column in range(parent.columnCount()):
                    child = parent.child(row, column)
                    yield child
                    if child.hasChildren():
                        stack.append(child)

(注意:此解决方案提供了更可预测的排序,并且速度更快)

用法:

root = self.treeview.model().invisibleRootItem()
for item in self.iterItems(root):
    print(item.text())

root 参数可以是 QStandardItemModel 中的任何项目。