QRadioButton Widget#

keywords: QRadioButton, RadioButton, Radio Button

Radio Widget 是单选按钮控件. 可以提供一组选项, 但是只允许用户选择一个.

ratio_widget_1.py
 1# -*- coding: utf-8 -*-
 2
 3"""
 4演示如何使用 ratio. 并且演示了如何正确使用 ``QRadioButton.toggled`` 的 signal.
 5"""
 6
 7import sys
 8from PySide6 import QtCore, QtWidgets
 9
10
11class MainWidget(QtWidgets.QWidget):
12    """
13    Ref:
14
15    - QRadioButton: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QRadioButton.html
16    - QButtonGroup: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QButtonGroup.html
17    """
18
19    def __init__(self, parent):
20        super().__init__(parent)
21        # define
22        # 在一个 parent 下的所有 Radio, 默认情况下都是 exclusive 的, 即只能有一个被选中.
23        # 如果你需要让在一个 parent 下的 Ratio 分组, 通常有两种做法:
24        # 1. 把他们放到另一个 widget 中
25        # 2. 使用 QButtonGroup
26        self.ratio_1_wgt = QtWidgets.QRadioButton("label 1-1", self)
27        self.ratio_1_wgt.toggled.connect(self.on_ratio_toggled_handler)
28        self.ratio_2_wgt = QtWidgets.QRadioButton("label 1-2", self)
29        self.ratio_2_wgt.toggled.connect(self.on_ratio_toggled_handler)
30
31        self.main_lay = QtWidgets.QHBoxLayout()  # Horizontal Box layout
32        self.main_lay.addWidget(self.ratio_1_wgt)
33        self.main_lay.addWidget(self.ratio_2_wgt)
34        self.setLayout(self.main_lay)
35
36    @QtCore.Slot()
37    def on_ratio_toggled_handler(self):
38        """
39        在定义 check / uncheck 的 signal 的时候, 这里有个问题是你需要所有的 Radio 都有一个 signal
40        这会导致多次重复触发的问题. 因为你选择一个 ratio 的时候, 其他的 ratio 也会自动改变状态,
41        等于是所有 ratio 的 toggler 都触发了 signal, 这是不必要的. 正确的做法是先判断当前的
42        ratio button 是不是 checked, 如果不是 checked 就不要执行后面的逻辑.
43        """
44        radio_button: QtWidgets.QRadioButton = self.sender()
45        if radio_button.isChecked():
46            print(
47                f"{self.ratio_1_wgt.isChecked() = }, {self.ratio_2_wgt.isChecked() = }"
48            )
49
50
51class MainWindow(QtWidgets.QMainWindow):
52    def __init__(self):
53        super().__init__()
54        self.main_wgt = MainWidget(self)
55        self.setCentralWidget(self.main_wgt)
56        self.setGeometry(
57            int(screen_width * 0.25),  # x, at 25% of screen width
58            int(screen_height * 0.25),  # y, at 25% of screen height
59            int(screen_width * 0.5),  # w, 50% screen width
60            int(screen_height * 0.5),  # h, 50% screen height
61        )
62        self.setWindowTitle("ratio_widget")
63        self.show()
64
65
66if __name__ == "__main__":
67    app = QtWidgets.QApplication(sys.argv)
68    screen_width, screen_height = app.screens()[0].size().toTuple()
69    main = MainWindow()
70    sys.exit(app.exec())
ratio_widget_2.py
 1# -*- coding: utf-8 -*-
 2
 3"""
 4演示如何对 ratio button 进行分组, 使得在一个组内, 最多只能有一个 ratio button 可以被 check.
 5你在 App 中可以看到, label 1-1 和 label 1-2 是一组, label 2-1 和 label 2-2 是一组.
 6"""
 7
 8import sys
 9from PySide6 import QtCore, QtWidgets
10
11
12class MainWidget(QtWidgets.QWidget):
13    """
14    Reference:
15
16    - QRadioButton: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QRadioButton.html
17    - QButtonGroup: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QButtonGroup.html
18    """
19
20    def __init__(self, parent):
21        super().__init__(parent)
22        # Define button group
23        # 注意 ``QButtonGroup`` 不是一个 widget, 它只是一个 container, 可以将里面的
24        self.button_group_1 = QtWidgets.QButtonGroup(self)
25        self.ratio_1_1_wgt = QtWidgets.QRadioButton("label 1-1", self)
26        self.ratio_1_1_wgt.toggled.connect(self.button_group_1_toggled_handler)
27        self.button_group_1.addButton(self.ratio_1_1_wgt)
28        self.ratio_1_2_wgt = QtWidgets.QRadioButton("label 1-2", self)
29        self.ratio_1_2_wgt.toggled.connect(self.button_group_1_toggled_handler)
30        self.button_group_1.addButton(self.ratio_1_2_wgt)
31
32        self.button_group_2 = QtWidgets.QButtonGroup(self)
33        self.ratio_2_1_wgt = QtWidgets.QRadioButton("label 2-1", self)
34        self.ratio_2_1_wgt.toggled.connect(self.button_group_2_toggled_handler)
35        self.button_group_2.addButton(self.ratio_2_1_wgt)
36        self.ratio_2_2_wgt = QtWidgets.QRadioButton("label 2-2", self)
37        self.ratio_2_2_wgt.toggled.connect(self.button_group_2_toggled_handler)
38        self.button_group_2.addButton(self.ratio_2_2_wgt)
39
40        self.main_lay = QtWidgets.QVBoxLayout()  # Vertical Box layout
41
42        self.button_group_1_lay = QtWidgets.QHBoxLayout()  # Horizontal Box layout
43        self.button_group_1_lay.addWidget(self.ratio_1_1_wgt)
44        self.button_group_1_lay.addWidget(self.ratio_1_2_wgt)
45        self.main_lay.addLayout(self.button_group_1_lay)
46
47        self.button_group_2_lay = QtWidgets.QHBoxLayout()  # Horizontal Box layout
48        self.button_group_2_lay.addWidget(self.ratio_2_1_wgt)
49        self.button_group_2_lay.addWidget(self.ratio_2_2_wgt)
50        self.main_lay.addLayout(self.button_group_2_lay)
51
52        self.setLayout(self.main_lay)
53
54    def print_radio_button_status(self):
55        print(
56            f"label 1-1 = {self.ratio_1_1_wgt.isChecked()}, "
57            f"label 1-2 = {self.ratio_1_2_wgt.isChecked()}, "
58            f"label 2-1 = {self.ratio_2_1_wgt.isChecked()}, "
59            f"label 2-2 = {self.ratio_2_2_wgt.isChecked()}"
60        )
61
62    @QtCore.Slot()
63    def button_group_1_toggled_handler(self):
64        radio_button: QtWidgets.QRadioButton = self.sender()
65        if radio_button.isChecked():
66            self.print_radio_button_status()
67
68    @QtCore.Slot()
69    def button_group_2_toggled_handler(self):
70        radio_button: QtWidgets.QRadioButton = self.sender()
71        if radio_button.isChecked():
72            self.print_radio_button_status()
73
74
75class MainWindow(QtWidgets.QMainWindow):
76    def __init__(self):
77        super().__init__()
78        self.main_wgt = MainWidget(self)
79        self.setCentralWidget(self.main_wgt)
80        self.setGeometry(
81            int(screen_width * 0.25),  # x, at 25% of screen width
82            int(screen_height * 0.25),  # y, at 25% of screen height
83            int(screen_width * 0.5),  # w, 50% screen width
84            int(screen_height * 0.5),  # h, 50% screen height
85        )
86        self.setWindowTitle("ratio_widget")
87        self.show()
88
89
90if __name__ == "__main__":
91    app = QtWidgets.QApplication(sys.argv)
92    screen_width, screen_height = app.screens()[0].size().toTuple()
93    main = MainWindow()
94    sys.exit(app.exec())
ratio_widget_3.py
  1# -*- coding: utf-8 -*-
  2
  3"""
  4演示如何对 ratio button 进行分组, 使得在一个组内, 最多只能有一个 ratio button 可以被 check.
  5你在 App 中可以看到, label 1-1 和 label 1-2 是一组, label 2-1 和 label 2-2 是一组.
  6
  7特殊的是, 在这个例子中, 我们用的是 ``QButtonGroup.buttonToggled`` 的 Signal. 在这个例子中
  8我们发现该方法失败了, 因为在一个 QButtonGroup 有几个 radio, 当任何 radio 改变时, 这个
  9Signal 就会被触发几次. 我们还是需要用 ``QRadioButton.toggled`` 的 Signal 来处理比较好.
 10"""
 11
 12import sys
 13from PySide6 import QtCore, QtWidgets
 14
 15
 16class MainWidget(QtWidgets.QWidget):
 17    """
 18    Reference:
 19
 20    - QRadioButton: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QRadioButton.html
 21    - QButtonGroup: https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QButtonGroup.html
 22    """
 23
 24    def __init__(self, parent):
 25        super().__init__(parent)
 26        # Define button group
 27        # 注意 ``QButtonGroup`` 不是一个 widget, 它只是一个 container, 可以将里面的
 28        self.button_group_1 = QtWidgets.QButtonGroup(self)
 29        self.ratio_1_1_wgt = QtWidgets.QRadioButton("label 1-1", self)
 30        self.button_group_1.addButton(self.ratio_1_1_wgt)
 31        self.ratio_1_2_wgt = QtWidgets.QRadioButton("label 1-2", self)
 32        self.button_group_1.addButton(self.ratio_1_2_wgt)
 33        self.button_group_1.buttonToggled.connect(self.button_group_1_toggled_handler)
 34
 35        self.button_group_2 = QtWidgets.QButtonGroup(self)
 36        self.ratio_2_1_wgt = QtWidgets.QRadioButton("label 2-1", self)
 37        self.button_group_2.addButton(self.ratio_2_1_wgt)
 38        self.ratio_2_2_wgt = QtWidgets.QRadioButton("label 2-2", self)
 39        self.button_group_2.addButton(self.ratio_2_2_wgt)
 40        self.button_group_2.buttonToggled.connect(self.button_group_2_toggled_handler)
 41
 42        self.main_lay = QtWidgets.QVBoxLayout()  # Vertical Box layout
 43
 44        self.button_group_1_lay = QtWidgets.QHBoxLayout()  # Horizontal Box layout
 45        self.button_group_1_lay.addWidget(self.ratio_1_1_wgt)
 46        self.button_group_1_lay.addWidget(self.ratio_1_2_wgt)
 47        self.main_lay.addLayout(self.button_group_1_lay)
 48
 49        self.button_group_2_lay = QtWidgets.QHBoxLayout()  # Horizontal Box layout
 50        self.button_group_2_lay.addWidget(self.ratio_2_1_wgt)
 51        self.button_group_2_lay.addWidget(self.ratio_2_2_wgt)
 52        self.main_lay.addLayout(self.button_group_2_lay)
 53
 54        self.setLayout(self.main_lay)
 55
 56    def print_radio_button_status(self):
 57        print(
 58            f"label 1-1 = {self.ratio_1_1_wgt.isChecked()}, "
 59            f"label 1-2 = {self.ratio_1_2_wgt.isChecked()}, "
 60            f"label 2-1 = {self.ratio_2_1_wgt.isChecked()}, "
 61            f"label 2-2 = {self.ratio_2_2_wgt.isChecked()}"
 62        )
 63
 64    @QtCore.Slot()
 65    def button_group_1_toggled_handler(self):
 66        print("trigger button_group_1_toggled_handler")
 67        button_group: QtWidgets.QButtonGroup = self.sender()
 68        for radio_wgt in button_group.buttons():
 69            if radio_wgt.isChecked():
 70                self.print_radio_button_status()
 71
 72    @QtCore.Slot()
 73    def button_group_2_toggled_handler(self):
 74        print("trigger button_group_2_toggled_handler")
 75        button_group: QtWidgets.QButtonGroup = self.sender()
 76        for radio_wgt in button_group.buttons():
 77            if radio_wgt.isChecked():
 78                self.print_radio_button_status()
 79
 80
 81class MainWindow(QtWidgets.QMainWindow):
 82    def __init__(self):
 83        super().__init__()
 84        self.main_wgt = MainWidget(self)
 85        self.setCentralWidget(self.main_wgt)
 86        self.setGeometry(
 87            int(screen_width * 0.25),  # x, at 25% of screen width
 88            int(screen_height * 0.25),  # y, at 25% of screen height
 89            int(screen_width * 0.5),  # w, 50% screen width
 90            int(screen_height * 0.5),  # h, 50% screen height
 91        )
 92        self.setWindowTitle("ratio_widget")
 93        self.show()
 94
 95
 96if __name__ == "__main__":
 97    app = QtWidgets.QApplication(sys.argv)
 98    screen_width, screen_height = app.screens()[0].size().toTuple()
 99    main = MainWindow()
100    sys.exit(app.exec())