Search code examples
pythonpython-3.xpyqtpyqt5qtreewidget

How to set the setCheckedState of a QTreeWidget child's child?


I have a QTreeWidget that has a hidden root, 2 children as headers, and 2 children underneath those children.

ROOT (HIDDEN)
  |
  |- HEADER 1 (CHILD, NOT CHECKABLE)
  |     |
  |     |- ITEM 11 (CHILD, CHECKABLE)
  |     |- ITEM 12 (CHILD, CHECKABLE)
  |
  |- HEADER 2 (CHILD)
  |     |
  |     | - ITEM 21 (CHILD, CHECKABLE)
  |     | - ITEM 22 (CHILD, CHECKABLE)

Using a variable from the item = {} dictionary I need to setCheckState of HEADER 1, ITEM 12. Currently I track the current selected label using self.CurrentIndexLabel, although that is probably irrelevant in this example. I have populated the tree like such:

TreeList = ({
    'Header1': (('Item11', 'Item12', )),
    'Header2': (('Item21', 'Item22', )),
})

item = {'Item12': {'ItemEnabled': 1}}  # 0 = No, 1 = Yes

for key, value in TreeList.items():
    parent = QTreeWidgetItem(self.ListTreeView, [key])
    for val in value:
        child = QTreeWidgetItem([val])
        child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
        child.setCheckState(0, Qt.Unchecked)
        parent.addChild(child)

Initially, I need to set whether the item is checked, or unchecked based on the item = {} dictionary that tacks variables for each item, and when the user unchecks the item, I need to change the item = {} dictionary to reflect whether or not the item is enabled.

I assume I need to use signal and slots to detect the change, but I can't seem to figure out how to flag an item in the list as checked, and I'm not sure how to reflect a user checking or unchecking an item in TreeList.

It would be ideal if I can track the checking or unchecking using 1 and 0 to update the dictionary item = {} with it's current state.

What would be the best way to accomplish this? I'm new to python, so please bear with me. I'm using Python 3.6 and PyQt5


Solution

  • When a QTreeWidgetItem is checked or unchecked, a QTreeWidget.itemChanged(item, column) signal is emitted. So you can use it and then update your item dict in the slot.

    And as said in a comment, I think the structure of the item dict you use is inapropriate. Using QTreeWidgetItem text value as a key (or still better, the QTreeWidgetItem object itself) would be easier, so a dict like item = {'Item12': {'ItemEnabled': True}}

    For example :

    from PyQt4 import QtCore, QtGui
    import sys
    
    
    class MyApplication(QtGui.QMainWindow):
        def __init__(self):
            super(MyApplication, self).__init__()
            self.item = {'Item12': {'ItemEnabled': True}}
            self.setupUi()
    
            TreeList = ({
                'Header1': ('Item11', 'Item12',),
                'Header2': ('Item21', 'Item22',),
            })
    
            for key, value in TreeList.items():
                parent = QtGui.QTreeWidgetItem(self.treeWidget, [key])
                for val in value:
                    child = QtGui.QTreeWidgetItem([val])
                    child.setFlags(child.flags() | QtCore.Qt.ItemIsUserCheckable)
                    child.setCheckState(0, QtCore.Qt.Checked if val in self.item else QtCore.Qt.Unchecked)
                    parent.addChild(child)
    
            self.treeWidget.itemChanged.connect(self.treeWidgetItemChanged)
    
        def setupUi(self):
            self.centralwidget = QtGui.QWidget(self)
            self.gridLayout = QtGui.QGridLayout(self.centralwidget)
            self.treeWidget = QtGui.QTreeWidget(self.centralwidget)
            self.gridLayout.addWidget(self.treeWidget)
            self.setCentralWidget(self.centralwidget)
    
        def treeWidgetItemChanged(self, widgetItem, column):
            print("Item {} is checked: {}".format(widgetItem, widgetItem.checkState(column) == QtCore.Qt.Checked))
            itemName = str(widgetItem.text(column))
            try:
                self.item[itemName]['ItemEnabled'] = widgetItem.checkState(column) == QtCore.Qt.Checked
            except KeyError:
                self.item[itemName] = {'ItemEnabled': widgetItem.checkState(column) == QtCore.Qt.Checked}
    
            print(self.item)
    
    
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        w = MyApplication()
        w.show()
        sys.exit(app.exec_())