Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

collect all items in QTreeview recursively

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()
like image 935
JokerMartini Avatar asked Dec 23 '22 21:12

JokerMartini


1 Answers

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.

like image 115
ekhumoro Avatar answered Dec 31 '22 20:12

ekhumoro