I'm using Qt Designer and pyqt code to write an app.
I have a very simple question: in my UI I have 2 checkboxes and what I need is to set the first checkbox as always unchecked when the second checkbox is unchecked.
In other words the first checkbox can be checked only when the second checkbox is checked, but the second checkbox can be checked also if the first one is not checked.
In Qt Designer I have not find an easy way to do that with the Signals/Slots function.
I had a look in the Qt API and I tried to write some code:
class CreateRIVLayerDialog(QDialog, FORM_CLASS):
def __init__(self, iface)
# some more code here...
if self.addCheckDB.isChecked():
self.addCheck.setChecked(False)
but without results.
Does anybody have some hints?
Thanks
The simplest way is with two signal connections, one of which can be done in Qt Designer.
Your design requires that "the first checkbox can be checked only when the second checkbox is checked". This is equivalent to saying the first checkbox should be disabled when the second checkbox is unchecked. Disabling the checkbox makes it clear to the user that the option is unavailable.
So in Qt Designer, you should connect the toggled
signal of checkbox2
to the setEnabled
slot of checkbox1
. (It may also be necessary to set the initial enabled
state of checkbox1
in Qt Designer as well).
Then, in your code, you should make a second connection, like this:
self.checkbox2.toggled.connect(
lambda checked: not checked and self.checkbox1.setChecked(False))
This will clear the checked state of checkbox1
whenever checkbox2
is unchecked.
If you wanted to do the whole thing in code, it would look like this:
self.checkbox1.setEnabled(False)
self.checkbox2.toggled.connect(self.checkbox1.setEnabled)
self.checkbox2.toggled.connect(
lambda checked: not checked and self.checkbox1.setChecked(False))
Just use signals. You are correct when saying that you cannot directly do that via the designer since you have to invert the checked property. The easiest and most readable way that comes to my mind is using a common slot plus an internal member variable that holds the checked state for both:
Add self._toggle = INITIAL_VALUE
to your class - the INITIAL_VALUE holds a boolean value, which you use to check/uncheck your checkboxes
self._toggle = True
self.check1 = QCheckBox('Check 1', self)
self.check1.setChecked(self._toggle)
self.check2 = QCheckBox('Check 2', self)
self.check2.setChecked(not self._toggle)
Add a slot:
@pyqtSlot()
def toggle(self):
self._toggle = not self._toggle
self.check1.setChecked(self._toggle)
self.check2.setChecked(not self._toggle)
Connect the clicked
signal of both checkboxes to this slot.
Warning! Do not use the stateChanged
signal here or you will start an infinite recursion. :3
self.check1.clicked.connect(self.toggle)
self.check2.clicked.connect(self.toggle)
What I'm doing here is basically taking over the change of the state of both checkboxes and do it manually using the value of self._toggle
for the first checkbox and the inverted value of self._toggle
for the second checkbox.
If you want less inverting inside the slot the following also works though it is less readable omho:
@pyqtSlot()
def toggle(self):
self.check2.setChecked(self._toggle) # Old value of our check1 becomes the value of check2
self._toggle = not self._toggle # Invert
self.check1.setChecked(self._toggle) # New value is assigned to check1
Note: You can also use isChecked()
inside the slot and do all of the above without the extra variable however I find this more readable and with much less function calls (every isChecked()
and setChecked()
is a function call)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With