Python Forum

Full Version: PyQt4 handle dynamic checkbox click
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm working on a screen that displays a QTableWidget. Each row in the table has a string 'Part Role Name' followed by 5 checkboxes. The number of rows in the table change based on Json results returned from a web API call. So the table is sized and the rows added dynamically. I have a class that represents each table row. I'm having trouble wiring up a given checkbox to its corresponding field for the statechanged event. I can tell the event is firing and what state it is changing to, I just don't know which field to update. Here is my Python class:

from PyQt4 import QtCore, QtGui

class PartRoleShadow(object):
    """Part role shadow settings for rendering"""

    def __init__(self, name, caster, catcher, excluded, hidden, render):
        self.part_role_name = name
        self.shadow_caster = caster
        self.shadow_catcher = catcher
        self.excluded = excluded
        self.hidden = hidden
        self.render = render

    def _widget(self, flag):
        cell_widget = QtGui.QWidget()
        chk_bx = QtGui.QCheckBox()
        chk_val = QtCore.Qt.Unchecked
        if flag:
            chk_val = QtCore.Qt.Checked
        chk_bx.setCheckState(chk_val)
        chk_bx.stateChanged.connect(self.set_value)
        lay_out = QtGui.QHBoxLayout(cell_widget)
        lay_out.addWidget(chk_bx)
        lay_out.setAlignment(QtCore.Qt.AlignCenter)
        lay_out.setContentsMargins(0, 0, 0, 0)
        cell_widget.setLayout(lay_out)
        return cell_widget

    def set_value(self, state):
        if state == QtCore.Qt.Checked:
            bvalue = True
        else:
            bvalue = False
        print("State Changed. It is now " + str(bvalue))
        print(self)

    def get_shadow_caster_checkbox_widget(self):
        return self._widget(self.shadow_caster)

    def get_shadow_catcher_checkbox_widget(self):
        return self._widget(self.shadow_catcher)

    def get_excluded_checkbox_widget(self):
        return self._widget(self.excluded)

    def get_hidden_checkbox_widget(self):
        return self._widget(self.hidden)

    def get_render_checkbox_widget(self):
        return self._widget(self.render)
Print results from checking/unchecking a box:

State Changed. It is now True
<PartRoleShadow.PartRoleShadow object at 0x038180B0>
State Changed. It is now False
<PartRoleShadow.PartRoleShadow object at 0x038180B0>
I don't know if this is the best approach, but it works. I stripped the _widget method out of the class and created a new class called CheckBox. I then made each of the boolean properties of the PartRoleShadow class instances of CheckBox, like so:

class PartRoleShadow(object):
    """Part role shadow settings for rendering"""

    def __init__(self, name, caster, catcher, excluded, hidden, render):
        self.part_role_name = name
        self.shadow_caster = cb.CheckBox(name, "caster", caster)
        self.shadow_catcher = cb.CheckBox(name, "catcher", catcher)
        self.excluded = cb.CheckBox(name, "excluded", excluded)
        self.hidden = cb.CheckBox(name, "hidden", hidden)
        self.render = cb.CheckBox(name, "render", render)
I extended the definition of the checkbox class to include the row name and column name. This allows me to easily reference the cell to retrieve the value.

class CheckBox(QtGui.QWidget):
    def __init__(self, rowname, colname, flag=False):
        QtGui.QWidget.__init__(self)
        chk_bx = QtGui.QCheckBox()
        chk_val = QtCore.Qt.Unchecked
        if flag:
            chk_val = QtCore.Qt.Checked
        chk_bx.setCheckState(chk_val)
        chk_bx.stateChanged.connect(self.item_clicked)
        chk_bx.setObjectName(rowname + colname)
        lay_out = QtGui.QHBoxLayout(self)
        lay_out.addWidget(chk_bx)
        lay_out.setAlignment(QtCore.Qt.AlignCenter)
        lay_out.setContentsMargins(0, 0, 0, 0)
        self.setLayout(lay_out)
An example of retrieving a checkbox value from a cell:

        # retrieve checkbox values for each row
        for r in range(widget.rowCount()):
            # get part role name for cell lookup key
            name = widget.item(r, 0).text()
            # get the checkbox by constructing a lookup key for the row & column
            item = widget.findChild(QtGui.QCheckBox, name + "caster")
            print(item.checkState())
If anybody has a different approach, I would be happy to see it.