I have two check boxes which are part of a button group. I want to be able to select one, the other, or none. To this end, I have the following:
import sys
from PySide2 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Check Problems')
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.check1_label = QtWidgets.QLabel('Check1')
self.check1 = QtWidgets.QCheckBox()
self.check2_label = QtWidgets.QLabel('Check2')
self.check2 = QtWidgets.QCheckBox()
self.check_buttongroup = QtWidgets.QButtonGroup()
self.check_buttongroup.addButton(self.check1)
self.check_buttongroup.addButton(self.check2)
self.check_buttongroup.buttonPressed.connect(self.check_buttongroup_pressed)
def init_layout(self):
check1_layout = QtWidgets.QHBoxLayout()
check1_layout.addWidget(self.check1_label)
check1_layout.addWidget(self.check1)
check2_layout = QtWidgets.QHBoxLayout()
check2_layout.addWidget(self.check2_label)
check2_layout.addWidget(self.check2)
check_layout = QtWidgets.QVBoxLayout()
check_layout.addLayout(check1_layout)
check_layout.addLayout(check2_layout)
# Central widget
centralWidget = QtWidgets.QWidget()
centralWidget.setLayout(check_layout)
self.setCentralWidget(centralWidget)
def check_buttongroup_pressed(self, button):
print('\nIs this check1? ', button == self.check1, flush=True)
print('Status when pressed: ', button.isChecked(), flush=True)
if button.isChecked():
print('Button isChecked: ', button.isChecked(), flush=True)
print('Changing button check state...', flush=True)
button.group().setExclusive(False)
button.setChecked(False)
print('Button isChecked: ', button.isChecked(), flush=True)
button.group().setExclusive(True)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
No boxes are checked initially. Clicking check1
produces:
Is this check1? True
Status when pressed: False
This is expected. The box was unchecked initially. Having clicked it, however, the box is now checked. When I click check1
again, I expect it to uncheck, leaving both boxes unchecked. Now, clicking check1
, I see:
Is this check1? True
Status when pressed: True
Button isChecked: True
Changing button check state...
Button isChecked: False
This is as expected. What is unexpected, however, is check1
is still checked!
Clicking a third time produces:
Is this check1? True
Status when pressed: True
Button isChecked: True
Changing button check state...
Button isChecked: False
Why does check1
not uncheck as expected? Is button.isChecked()
lying to me or is setChecked(False)
not doing its job? Am I mistaken somewhere?
I have tried this with PySide2==5.15.0, PySide2==5.13, PySide6, and PyQt5==5.15 with the same result, so I assume this is how it's supposed to behave and not some Qt implementation error.
The solution is to change the property exclusive to False if when the buttonPressed signal is emitted the button is checked and set that property to true when the buttonClicked is emitted.
def init_widgets(self):
# ...
self.check_buttongroup = QtWidgets.QButtonGroup()
self.check_buttongroup.addButton(self.check1)
self.check_buttongroup.addButton(self.check2)
self.check_buttongroup.buttonPressed.connect(self.handle_pressed)
self.check_buttongroup.buttonClicked.connect(self.handle_clicked)
def handle_pressed(self, button):
button.group().setExclusive(not button.isChecked())
def handle_clicked(self, button):
button.group().setExclusive(True)