Несколько групп радиокнопок связаны, что приводит к странному поведению

Моя программа генерирует формы на лету на основе данных SQL. Я делаю два переключателя и запись QLineEdit рядом с ними. Когда переключатель справа установлен, QLineEdit включен правильно. Проблема возникает из-за того, что радиокнопки связываются и вызывают эксклюзивные действия между собой. При запуске программы они выглядят так: Запуск программы

Затем, когда я нажимаю первое «Нет», оно меняется, как я ожидаю, и включает QLineEdit. Нормальное поведение

Теперь я хочу также нажать «Нет» для «Серийный номер: RC1». Здесь поведение начинает идти не так. Кнопка «Нет» нажимается и отменяет выбор всей строки выше.

Отменяет выбор верхней строки

Если я попытаюсь снова нажать «Нет» в верхней строке, «да» во второй строке отменит выбор.

отменяет выбор второй строки

Наконец, я могу щелкнуть переключатели «Выбрано» и отменить выбор всего, пока не останется один активный переключатель. На данный момент у меня не может быть больше выбранных кнопок, чем только эта. Щелчок по невыбранной кнопке активирует ее и отменит выбор ранее активной кнопки.

Осталась одна выбранная кнопка

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

# !/user/bin/env python
import os
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *


class Radio(QDialog):
    def __init__(self, app):
        super(Radio, self).__init__()
        self.bundle_dir = os.path.dirname(__file__)
        gui_path = os.path.join(self.bundle_dir, 'ui', 'radio_bt_test.ui')
        self.ui = uic.loadUi(gui_path, self)
        self.num_of_row = 4
        self.formLayout = self.findChild(QFormLayout, "formLayout")
        self.radio_bt_lineEdit_connections = dict()  # to help link the radio buttons and lineEdit
        self.add_rows()
        self.show()

    def add_rows(self):
        """
        Adds pairs of radio buttons with a lineEdit to each row of the form layout
        :return: 
        """
        for i in range(self.num_of_row):
            lbl = QLabel("Label#" + str(i))
            hbox = QHBoxLayout()
            buttons = self.new_radio_pair()
            entry = self.new_entry("Value if No")
            entry.setEnabled(False)
            self.radio_bt_lineEdit_connections[buttons[-1]] = entry
            # adding connection to dictionary for later event handling
            buttons[-1].toggled.connect(self.radio_bt_changed)
            for button in buttons:
                hbox.addWidget(button)
            hbox.addWidget(entry)
            self.formLayout.addRow(lbl, hbox)

    def new_radio_pair(self, texts=('Yes', 'No')) -> list:
        """
        Makes a pair of radio buttons in a button group for creating data entries in "Part" grouping on the fly
        :param texts: The texts that will go on the two buttons. The more texts that are added to make more radio buttons
        :return: A list with QRadioButtons that are all part of the same QButtonGroup
        """
        group = QButtonGroup()
        buttons = []
        for text in texts:
            bt = QRadioButton(text)
            bt.setFont(QFont('Roboto', 11))
            if text == texts[0]:
                bt.setChecked(True)
            group.addButton(bt)
            buttons.append(bt)

        return buttons

    def radio_bt_changed(self) -> None:
        """
        Helps the anonymous radio buttons link to the anonymous QLineEdits that are made for data fields
        :return: None
        """
        sender = self.sender()
        assert isinstance(sender, QRadioButton)
        lineEdit = self.radio_bt_lineEdit_connections[sender]
        assert isinstance(lineEdit, QLineEdit)
        if sender.isChecked():
            lineEdit.setEnabled(True)
        else:
            lineEdit.setEnabled(False)
            lineEdit.clear()

    def new_entry(self, placeholder_text: str = "") -> QLineEdit:
        """
        Makes a new QLineEdit object for creating data entries in "Part" grouping on the fly
        :return: A new QLineEdit with appropriate font and size policy
        """
        entry = QLineEdit()
        entry.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        entry.setFont(QFont('Roboto', 11))
        entry.setStyleSheet("background-color: rgb(239, 241, 243);")
        # with style sheets, past anything in here between the css tags
        entry.setMaxLength(15)
        entry.setPlaceholderText(placeholder_text)
        return entry


def main():
    app = QApplication(sys.argv)
    radio = Radio(app)
    sys.exit(app.exec())

main()

Может быть, это потому, что я объявляю QButtonGroup, а затем забываю о них? Приходит ли сборщик мусора и стирает их, потому что мне не назначена переменная, или есть другая проблема, которую я упускаю.

Пользовательский интерфейс был разработан в QtDesigner и представляет собой просто диалоговое окно с макетом формы.

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>491</width>
    <height>382</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <property name="styleSheet">
   <string notr="true">background-color: rgb(219, 221, 223);</string>
  </property>
  <widget class="QWidget" name="formLayoutWidget">
   <property name="geometry">
    <rect>
     <x>80</x>
     <y>40</y>
     <width>301</width>
     <height>291</height>
    </rect>
   </property>
   <layout class="QFormLayout" name="formLayout"/>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>


person Lacrosse343    schedule 10.06.2020    source источник
comment
Хорошо, я добавил код, который позволяет любому копировать, вставлять и запускать программу.   -  person Lacrosse343    schedule 12.06.2020


Ответы (1)


Объект, который следует использовать, чтобы сделать кнопки строк монопольными, называется «группа», но это локальная переменная, которая уничтожается, когда завершается выполнение метода new_radio_pair, в результате чего он ведет себя не так, как предполагалось ранее.

Решение состоит в том, чтобы продлить жизненный цикл, и для этого есть несколько вариантов, таких как сделать его атрибутом класса, добавить его в контейнер или класс, который имеет более длительный жизненный цикл, или, в случае QObjects, передать ему другой QObject. как родитель (например, self), который имеет более длительный жизненный цикл, и это лучшее решение для этого случая:

group = QButtonGroup(self)
person eyllanesc    schedule 12.06.2020