PyQt - get list of all checked in QTreeWidget

10.9k views Asked by At

I am building a simple application to open up a folder of data and plot that data. Importing the data updates a QTreeWidget that shows which signals are available to plot. Ex:

enter image description here

The QTreeWidget is populated after the data is imported using:

def update_treeWidget(self):
    headers = self.df['voltage recording'].columns[1:]
    sweeps = self.df['voltage recording'].index.levels[0]

    for header in headers:
        parent_item = QtWidgets.QTreeWidgetItem(self.treeWidget)
        parent_item.setCheckState(0, QtCore.Qt.Unchecked)
        parent_item.setText(0, header)

        for sweep in sweeps:
            child_item = QtWidgets.QTreeWidgetItem(parent_item)
            child_item.setCheckState(0, QtCore.Qt.Unchecked)
            child_item.setText(0, sweep)

It is unclear to me, though, how I would check the checked status for any of the items now in the tree.

So my two questions are:

  1. How would I refer to any part of that tree to check it's checked status (either the parent, or the various children of a parent)

  2. Is there a way to simply return a list of all of the boxes that are checked? If I can figure out the answer to Question 1 I can obviously create a function where, every time a box is checked it is added to a list (and removed from that list if it is unchecked). But since the goal here is simply to plot all of the checked signals, the most straightforward thing to me (logically anyway) is upon hitting the "Plot" button the interface first checks to see which signals boxes are checked and then plots those signals.

In all of the examples I have seem the tree items are explicitly declared (i.e. item_1, item_2), so referring to them is simple. Because of how I am populating the tree, though, I don't understand how to do that.

If this is an incorrect approach to populating the tree in the first place, please let me know and/or point me in the direction of a more correct approach.

Thanks

Edit:

This is very similar to: PyQT QTreeWidget iterating

which is what I based my answer off of.

3

There are 3 answers

1
dan_g On

Figured it out. This at least achieves what I need it to achieve:

def find_checked(self):
    checked = dict()
    root = self.treeWidget.invisibleRootItem()
    signal_count = root.childCount()

    for i in range(signal_count):
        signal = root.child(i)
        checked_sweeps = list()
        num_children = signal.childCount()

        for n in range(num_children):
            child = signal.child(n)

            if child.checkState(0) == QtCore.Qt.Checked:
                checked_sweeps.append(child.text(0))

        checked[signal.text(0)] = checked_sweeps

    return checked
0
hollebread On

Five years later I was searching for an answer to your second question. While dan_g's code was very helpful I believe it will not list all items if the tree depth is greater than 2. I created a recursive version that will list all selected items regardless of their level in the tree.

    def get_selected_items(self):
        checked_items = []
        def recurse(parent_item):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                grand_children = child.childCount()
                if grand_children > 0:
                    recurse(child)
                if child.checkState(0) == Qt.Checked:
                    checked_items.append(child.text(0))

        recurse(self.ui.treeWidget.invisibleRootItem())
        return checked_items

Or in my case if you only want to list selected items at the leaves of the tree just add an else statement.

    def get_selected_leaves(self):
        checked_items = []
        def recurse(parent_item):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                grand_children = child.childCount()
                if grand_children > 0:
                    recurse(child)
                else: 
                    if child.checkState(0) == Qt.Checked:
                        checked_items.append(child.text(0))

        recurse(self.ui.treeWidget.invisibleRootItem())
        return checked_items

In either case the function calls itself whenever it finds an item that has children until it traverses the entire tree.

0
vellan On

Next solution can be used:

for item in self.QTreeWidget.findItems("", Qt.MatchContains | Qt.MatchRecursive):
    if (item.rowCount() == 0 and item.checkState()>0):
        print (item.text(),item.checkState())