Marc
Marc

Reputation: 29

QCheckBox to check/uncheck all QCheckboxes from another class in PyQt5

I have two QWidget classes: Widget1 and Widget2, and I would like to have a QCheckBox in the first class (Widget1) that can check/uncheck all the QcheckBoxes generated by the second class (Widget2). Is there a way to do this? Many thanks in advance for your help.

class Widget1(QWidget):
    def __init__(self, ids):
        super().__init__()
        self.ids = ids  # ids is a list of list [[1, 1], [2, 2], [3, 3], ..., [n, n] generated elsewhere in the code 
        self.initUI()

    def initUI(self):
        self.widget1_layout = QVBoxLayout()
        self.setLayout(self.Widget1_Layout)

        self.master_checkbox = QCheckBox("Select all")
        self.master_checkbox.stateChanged.connect(self.selectAll)
        self.widget1_layout.addWidget(self.master_checkbox)

        for i, id in enumerate(self.ids):
            self.singleID_checkbox = Widget2(self, i, id)
            self.widget1_layout.addWidget(self.singleID_checkbox)

     def selectAll(self):
        if self.master_checkbox.isChecked():
            function_that_check_all_Widget2_checkboxes()
        else:
            function_that_UNcheck_all_Widget2_checkboxes()



class Widget2(QWidget):
    def __init__(self, parent, i, id, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.i = i
        self.id = id
        self.initUI()
    
    def initUI(self):
        self.singleIDcheckbox_layout = QGridLayout(self)
        self.singleIDcheckbox = QCheckBox(str(self.id))
        self.singleIDcheckbox_layout.addWidget(self.singleIDcheckbox, self.i, 0)

The two functions

function_that_check_all_Widget2_checkboxes()

and

function_that_UNcheck_all_Widget2_checkboxes()

do not exist.

They are are here as examples to better present my problem, as I guess that this is where I should put some code to do what I'd like to achieve.

Upvotes: 0

Views: 602

Answers (1)

musicamante
musicamante

Reputation: 48231

The simplest solution is to add each widget to a list whenever you're creating them, then check/uncheck them according to the "master" state.

Note that:

  1. when creating multiple objects there's no use in setting them as instance members: the purpose of an instance attribute is to have a persistent reference to an object, if you continously overwrite that reference you lose that benefit;
  2. most signals provide arguments, especially those relating "changes"; calling isChecked() is unnecessary, as stateChanged already returns the current state, you just need to add the argument to the function;
  3. unless you're requiring a tristate checkbox, the correct signal is toggled (which returns a bool state), not the stateChanged (which returns a Qt.CheckState flag that has 2 for the checked state);
class Widget1(QWidget):
    # ...
    def initUI(self):
        self.widget1_layout = QVBoxLayout(self)

        self.master_checkbox = QCheckBox("Select all")
        self.master_checkbox.toggled.connect(self.selectAll)
        self.widget1_layout.addWidget(self.master_checkbox)

        self.checkboxes = []
        for i, id in enumerate(self.ids):
            singleID_checkbox = Widget2(self, i, id)
            self.widget1_layout.addWidget(singleID_checkbox)
            self.checkboxes.append(singleID_checkbox)

    def selectAll(self, state):
        for check in self.checkboxes:
            check.setChecked(state)


class Widget2(QWidget):
    # ...
    def setChecked(self, state):
        self.singleIDcheckbox.setChecked(state)

Note that, since you're using a specialized class, you could also use findChildren, which returns all child objects that are instances of the specified class:

    def selectAll(self, state):
        for check in self.findChildren(Widget2):
            check.setChecked(state)

Use the above with care, though, as by default it looks recursively through the whole object tree, so using a list is still a better solution.

Upvotes: 1

Related Questions