В вашем коде есть концептуальная ошибка: вы создаете новую RadioButtonGroup, которая является виджетом, но вы ею не пользуетесь.
До тех пор, пока каждое поле группы будет содержать только радиокнопки, нет необходимости создавать новый виджет (особенно если вы его не используете); вам просто нужно создать макет, если у группового блока его еще нет.
Существует как минимум два возможных подхода к вашему вопросу.
Для них обоих я всегда использую существующий rad ios если возможно, чтобы избежать ненужного уничтожения объекта каждый раз, когда параметры меняются, поэтому они удаляются только при уменьшении количества параметров. Это также позволяет избежать ненужных обновлений макета (особенно, если число параметров одинаково).
Я также сохранил логический «интерфейс» согласованным, обеспечив тот же метод и поведение update_options(groupBox, options)
.
Группа на основе QObject
В этой реализации я создаю объект, который действует как интерфейс, отвечающий за создание QButtonGroup и настройку параметров, а также предоставляет сигналы для изменения состояния или текущего проверенного радио.
class RadioButtonGroup(QtCore.QObject):
optionToggled = QtCore.pyqtSignal(object, int, bool)
optionChanged = QtCore.pyqtSignal(object, int)
def __init__(self, radio_group_box, button_list):
super().__init__()
self.groupBox = radio_group_box
layout = radio_group_box.layout()
self.buttonGroup = QtWidgets.QButtonGroup(self)
self.buttonGroup.buttonToggled[int, bool].connect(self.changed)
if layout is None:
layout = QtWidgets.QVBoxLayout(radio_group_box)
for i, text in enumerate(button_list, 1):
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
self.buttonGroup.addButton(radio, i)
def button(self, id):
return self.buttonGroup.button(id)
def changed(self, i, state):
self.optionToggled.emit(self, i, state)
if state:
self.optionChanged.emit(self, i)
def selected_button(self):
return self.buttonGroup.checkedId()
def update_options(self, button_list):
layout = self.groupBox.layout()
# this method will keep the current checked radio as checked, if you want
# to reset it everytime, just uncomment the next commented lines
#self.buttonGroup.setExclusive(False)
for i, text in enumerate(button_list, 1):
radio = self.buttonGroup.button(i)
if radio:
#radio.setChecked(False)
radio.setText(text)
else:
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
self.buttonGroup.addButton(radio, i)
#self.buttonGroup.setExclusive(True)
if len(button_list) == len(self.buttonGroup.buttons()):
return
# there are more radios than needed, remove them
for radio in self.buttonGroup.buttons():
id = self.buttonGroup.id(radio)
if id > i:
self.buttonGroup.removeButton(radio)
radio.deleteLater()
class ObjectBased(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('buttongroup.ui', self)
self.pushButton.clicked.connect(self.setOptions)
self.groupBoxes = self.groupBox1, self.groupBox2, self.groupBox3
self.radioButtonGroups = []
for box in self.groupBoxes:
group = RadioButtonGroup(box,
['Option {}'.format(o + 1) for o in range(randrange(1, 10))])
self.radioButtonGroups.append(group)
group.optionChanged.connect(self.optionChanged)
def setOptions(self):
buttonGroup = self.radioButtonGroups[self.comboBox.currentIndex()]
options = ['Option {}'.format(o + 1) for o in range(self.spinBox.value())]
buttonGroup.update_options(options)
def optionChanged(self, radioButtonGroup, id):
groupBox = radioButtonGroup.groupBox
print('{} checked {} ({})'.format(
groupBox.title(), id, radioButtonGroup.button(id).text()))
Автономный
В этом режиме логики c находятся внутри класса окна. Хотя этот подход немного проще, чем другой, нам не хватает уникального «интерфейса», который может быть полезен для доступа из внешних объектов.
class SelfContained(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('buttongroup.ui', self)
self.pushButton.clicked.connect(self.setOptions)
self.radioButtonGroups = []
for g, groupBox in enumerate((self.groupBox1, self.groupBox2, self.groupBox3)):
buttonGroup = QtWidgets.QButtonGroup(self)
self.radioButtonGroups.append((groupBox, buttonGroup))
buttonGroup.buttonToggled[int, bool].connect(lambda id, state, g=g: self.optionChanged(g, id, state))
self.update_options(g, ['Option {}'.format(o + 1) for o in range(randrange(1, 10))])
def update_options(self, groupId, button_list):
groupBox, buttonGroup = self.radioButtonGroups[groupId]
layout = groupBox.layout()
if layout is None:
layout = QtWidgets.QVBoxLayout(groupBox)
# as above...
#buttonGroup.setExclusive(False)
for i, text in enumerate(button_list, 1):
radio = buttonGroup.button(i)
if radio:
#radio.setChecked(False)
radio.setText(text)
else:
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
buttonGroup.addButton(radio, i)
#buttonGroup.setExclusive(True)
if len(button_list) == len(buttonGroup.buttons()):
return
for radio in buttonGroup.buttons():
id = buttonGroup.id(radio)
if id > i:
buttonGroup.removeButton(radio)
radio.deleteLater()
def setOptions(self):
groupId = self.comboBox.currentIndex()
options = ['Option {}'.format(o + 1) for o in range(self.spinBox.value())]
self.update_options(groupId, options)
def optionChanged(self, groupId, id, state):
if state:
groupBox, buttonGroup = self.radioButtonGroups[groupId]
print('{} checked {} ({})'.format(groupBox.title(), id, buttonGroup.button(id).text()))