PyQt5: Как сбросить содержимое QtWidgets.QGroupBox - PullRequest
0 голосов
/ 06 марта 2020

У меня есть класс RadioButtonWidget, который получает список имен (button_list) и QtWidgets.QGroupBox (radio_group_box) и создает переключатель для каждого имени. Проблема у меня в том, что после создания кнопок я не могу их поменять. То есть, если я снова позвоню в класс с другим списком имен, ничего не изменится. Мне нужно создать функцию внутри моего класса, чтобы удалить все существующие переключатели, чтобы я мог добавить новый список внутри него.

Я пытался сделать radio_group_box.deleteLater() вне класса, но это удаляет всю коробку.

class RadioButtonWidget(QtWidgets.QWidget):
    def __init__(self, radio_group_box, button_list):
        super().__init__()
        self.radio_group_box = radio_group_box
        self.radio_button_group = QtWidgets.QButtonGroup()

        #create the radio buttons
        self.radio_button_list = []
        for each in button_list:
            self.radio_button_list.append(QtWidgets.QRadioButton(each))

        if button_list != []:
            #set the default checked item
            self.radio_button_list[0].setChecked(True)

        #create layout for radio buttons and add them
        self.radio_button_layout = QtWidgets.QVBoxLayout()

        # add buttons to the layout and button group
        counter = 1
        for each in self.radio_button_list:
            self.radio_button_layout.addWidget(each)
            self.radio_button_group.addButton(each)
            self.radio_button_group.setId(each,counter)
            counter += 1

        # add radio buttons to the group box
        self.radio_group_box.setLayout(self.radio_button_layout)

    def selected_button(self):
        return self.radio_button_group.checkedId()

Ответы [ 2 ]

3 голосов
/ 06 марта 2020

Вместо удаления переключателей вы можете создать совершенно новую раскладку переключателей и установить ее для группового блока точно так, как вы это делали в конструкторе. Вот пример, где функция set_group_box_buttons удалит существующий макет из radio_group_box (что делается путем установки его в временный виджет) и добавит новый с новыми кнопками.

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class RadioButtonWidget(QWidget):

    def __init__(self, radio_group_box, button_list):
        super().__init__()
        self.radio_group_box = radio_group_box
        self.set_group_box_buttons(button_list)

        grid = QGridLayout(self)
        grid.addWidget(self.radio_group_box)

    def selected_button(self):
        return self.radio_button_group.checkedId()

    def set_group_box_buttons(self, button_list):
        self.radio_button_group = QButtonGroup()
        self.radio_button_list = [QRadioButton(x) for x in button_list]
        if button_list:
            self.radio_button_list[0].setChecked(True)

        if self.radio_group_box.layout():
            QWidget().setLayout(self.radio_group_box.layout())

        self.radio_button_layout = QVBoxLayout()
        for i, v in enumerate(self.radio_button_list):
            self.radio_button_layout.addWidget(v)
            self.radio_button_group.addButton(v)
            self.radio_button_group.setId(v, i)
        self.radio_group_box.setLayout(self.radio_button_layout)


class Template(QWidget):

    def __init__(self):
        super().__init__()
        self.rbw = RadioButtonWidget(QGroupBox('Radio Buttons'), ['Radio 1', 'Radio 2', 'Radio 3'])
        self.box = QLineEdit()
        self.box.returnPressed.connect(self.replace_buttons)
        grid = QGridLayout(self)
        grid.addWidget(self.rbw, 0, 0)
        grid.addWidget(self.box, 0, 1)

    def replace_buttons(self):
        self.rbw.set_group_box_buttons(self.box.text().split(', '))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = Template()
    gui.show()
    sys.exit(app.exec_())

Для демонстрации я добавил QLineEdit, который будет обновлять имена при нажатии клавиши ввода. До:

enter image description here

После:

enter image description here

1 голос
/ 06 марта 2020

В вашем коде есть концептуальная ошибка: вы создаете новую 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()))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...