Связывание radioButton и checkBox
У меня есть форма, которая хранит в себе radioButton и 4 checkBox'а.
Я пытался связать их так, чтобы при нажатии на radioButton, ставились флажки на всех checkBox, а при отжимании одного из флажков, radioButton потухала, но проблема в том, что когда нажимаю на radioButton флажки ставятся на все checkBox кроме первого,
а чтобы флажок поставился на первый checkBox приходится повторно нажимать на radioButton.
Кроме этого, при снятии флажка с одного из checkBox, флажки снимаются со всех.
Прошу, подскажите, как это можно вылечить?
Код:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(152, 237)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.radioButton = QtWidgets.QRadioButton(self.centralwidget)
self.radioButton.setObjectName("radioButton")
self.verticalLayout.addWidget(self.radioButton)
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox.setObjectName("checkBox")
self.verticalLayout.addWidget(self.checkBox)
self.checkBox_2 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox_2.setObjectName("checkBox_2")
self.verticalLayout.addWidget(self.checkBox_2)
self.checkBox_3 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox_3.setObjectName("checkBox_3")
self.verticalLayout.addWidget(self.checkBox_3)
self.checkBox_4 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox_4.setObjectName("checkBox_4")
self.verticalLayout.addWidget(self.checkBox_4)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 152, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.radioButton.setText(_translate("MainWindow", "ALL"))
self.checkBox.setText(_translate("MainWindow", "A"))
self.checkBox_2.setText(_translate("MainWindow", "B"))
self.checkBox_3.setText(_translate("MainWindow", "C"))
self.checkBox_4.setText(_translate("MainWindow", "D"))
class Test(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setupUi(self)
self.radioButton.toggled.connect(self.onClicked)
self.checkBox.toggled.connect(self.onChecked)
self.checkBox_2.toggled.connect(self.onChecked)
self.checkBox_3.toggled.connect(self.onChecked)
self.checkBox_4.toggled.connect(self.onChecked)
def onClicked(self):
if self.radioButton.isChecked():
self.checkBox.setChecked(True)
self.checkBox_2.setChecked(True)
self.checkBox_3.setChecked(True)
self.checkBox_4.setChecked(True)
elif not self.radioButton.isChecked():
self.checkBox.setChecked(False)
self.checkBox_2.setChecked(False)
self.checkBox_3.setChecked(False)
self.checkBox_4.setChecked(False)
def onChecked(self):
check = []
checkBoxs = self.findChildren(QCheckBox)
for checkBox in checkBoxs:
if checkBox.isChecked():
check.append(1)
if len(check) == 4:
self.radioButton.setChecked(True)
else:
self.radioButton.setChecked(False)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Test()
ui.show()
sys.exit(app.exec_())
Ответы (2 шт):
Заглядываем в документацию и отмечаем
This may be the result of a user action, click() slot activation, or because setChecked() is called.
А поскольку в onClicked для радиобатона у вас четыре раза вызывается setChecked, на каждый вызов будет сгенерирован и обработан сигнал toggled, в котором вы опять меняете checkState чекбоксов
Попробуйте так:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import *
class Custom_QGroupBox(QtWidgets.QGroupBox):
checkAllIfAny = True
def __init__(self, *args, **kwargs):
super(Custom_QGroupBox, self).__init__(*args, **kwargs)
self.setCheckable(True)
self.checkBoxes = []
self.toggled.connect(self.toggleCheckBoxes)
def addCheckBox(self, cb):
self.checkBoxes.append(cb)
cb.toggled.connect(self.update)
cb.destroyed.connect(lambda: self.removeCheckBox(cb))
def removeCheckBox(self, cb):
try:
self.checkBoxes.remove(cb)
cb.toggled.disconnect(self.update)
except:
pass
def allStates(self):
return [cb.isChecked() for cb in self.checkBoxes]
def toggleCheckBoxes(self):
if self.checkAllIfAny:
state = not all(self.allStates())
else:
state = not any(self.allStates())
for widget in self.children():
if not widget.isWidgetType():
continue
if not widget.testAttribute(QtCore.Qt.WA_ForceDisabled):
# восстановить включенное состояние, чтобы переопределить
# поведение setChecked(False) по умолчанию;
# предыдущие явные вызовы setEnabled(False) для целевого виджета
# будут игнорироваться
widget.setEnabled(True)
if widget in self.checkBoxes:
widget.setChecked(state)
def paintEvent(self, event):
opt = QtWidgets.QStyleOptionGroupBox()
self.initStyleOption(opt)
states = self.allStates()
if all(states):
# force the "checked" state
opt.state |= QtWidgets.QStyle.State_On
opt.state &= ~QtWidgets.QStyle.State_Off
else:
# force the "not checked" state
opt.state &= ~QtWidgets.QStyle.State_On
if any(states):
# force the "not unchecked" state and set the tristate mode
opt.state &= ~QtWidgets.QStyle.State_Off
opt.state |= QtWidgets.QStyle.State_NoChange
else:
# force the "unchecked" state
opt.state |= QtWidgets.QStyle.State_Off
painter = QtWidgets.QStylePainter(self)
painter.drawComplexControl(QtWidgets.QStyle.CC_GroupBox, opt)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.groupBox = Custom_QGroupBox('ALL')
layout = QtWidgets.QGridLayout(self.groupBox)
cb_text_labels = ["A", "B", "C", "D"]
for r, text in enumerate(cb_text_labels):
cb = QtWidgets.QCheckBox(f' {text}')
self.groupBox.addCheckBox(cb)
layout.addWidget(cb, r, 0)
main_layout = QtWidgets.QGridLayout(self)
main_layout.addWidget(self.groupBox)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setFont(QtGui.QFont("Times", 12, QtGui.QFont.Bold))
w = MainWindow()
w.resize(140, 240)
w.show()
sys.exit(app.exec_())


