collect all items in QTreeview recursively
Asked Answered
C

1

7

How can I collect all Qtreeview items so i can then iterate over them and apply necessary changes like display text updates, or color changes?

Is there an easy way to collect all of them using the 'match' method?

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())

test code:

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()
Camala answered 31/1, 2017 at 3:54 Comment(1)
Since you connect self.get_checked(), how does the other get_checked() get called?Tafia
I
10

Here is a recursive solution (requires 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)

Alternative recursive solution (for 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)

And here is an iterative solution (for 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)

(NB: this solution gives a more predictable ordering, and is a little faster)

Usage:

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

The root argument can be any item in a QStandardItemModel.

Illdisposed answered 31/1, 2017 at 7:26 Comment(2)
Keeping your solution there, what about python 2.7?Camala
@JokerMartini. I added some other solutions.Illdisposed

© 2022 - 2024 — McMap. All rights reserved.