有没有一种方法可以“冻结” PyQt5中复选框的状态?

时间:2020-10-28 20:25:44

标签: checkbox pyqt pyqt5

我希望在选中另一个复选框时自动选中一个复选框,并且在取消选中另一个复选框之前不被取消选中。 我认为“冻结”是实现此目的的简便方法,但我对其他解决方案也很感兴趣。 一个示例程序尝试一下将是:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QCheckBox

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(500, 50, 500, 500)
        self.box1 = QCheckBox('Box1', self)
        self.box1.setGeometry(250, 10, 50, 50)
        self.box1.stateChanged.connect(self.dothething)
        self.box2 = QCheckBox('Box2', self)
        self.box2.setGeometry(10, 10, 50, 50)
        self.show()
    
    def dothething(self):
        if not self.box2.isChecked():
            self.box2.toggle()
            self.box2.freeze()
        else: 
            self.box2.unfreeze()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ui = Window()
    sys.exit(app.exec_())

显然.freeze().unfreeze()函数不存在。

我也尝试过.setCheckable,但与此同时,CheckBox只能冻结为未检查状态,这与我想要的相反。

1 个答案:

答案 0 :(得分:0)

有各种可用选项。

最明显的是禁用该复选框,这是最好的选择,因为它向用户表明不能取消选中该复选框,同时仍显示已被选中

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(500, 50, 500, 500)
        central = QWidget()
        self.setCentralWidget(central)
        self.box1 = QCheckBox('Box1', self)
        self.box1.toggled.connect(self.dothething)
        self.box2 = QCheckBox('Box2', self)
        layout = QHBoxLayout(central)
        layout.addWidget(self.box1)
        layout.addWidget(self.box2)
        self.show()
    
    def dothething(self, checked):
        if checked:
            self.box2.setChecked(True)
            self.box2.setEnabled(False)
        else:
            self.box2.setEnabled(True)

请注意,在上面的示例中,我使用的是中央小部件并设置布局;这是因为您应该始终在QMainWindow中使用中央窗口小部件,并且因为使用固定的几何图形会出现很多个问题,因此始终应首选布局管理器;例如,在这种情况下,我无法区分box1和box2,因为您使用的几何形状导致将数字隐藏在标签中。请记住,您在屏幕上看到的很少是其他人看到的。

更简单的选择是如果另一个被选中,则再次选中该框;无论用户使用鼠标还是键盘,这都将有效:

class Window(QMainWindow):
    def __init__(self):
        # ...

        self.box2.toggled.connect(self.verifyBox2)

    def verifyBox2(self, checked):
        if not checked and self.box1.isChecked():
            self.box2.setChecked(True)

    def dothething(self, checked):
        if checked:
            self.box2.setChecked(True)

仅出于完整性考虑,还有其他两种可能性,但请记住,这两种情况均依赖于鼠标事件,因此,如果用户使用键盘导航(通过制表符或助记符)并按空格复选框仍将被切换。

第一种可能性是设置WA_TransparentForMouseEvents标志,该标志将忽略所有鼠标事件:

class Window(QMainWindow):
    # ...
    def dothething(self, checked):
        if checked:
            self.box2.setChecked(True)
            self.box2.setAttribute(Qt.WA_TransparentForMouseEvents, True)
        else:
            self.box2.setAttribute(Qt.WA_TransparentForMouseEvents, False)

或者,您可以使用事件过滤器忽略左键单击事件(包括双击,因为QCheckBox也可以使用它们进行切换):

class Window(QMainWindow):
    def __init__(self):
        # ...
        self.box2.installEventFilter(self)

    def eventFilter(self, source, event):
        if source == self.box2:
            if event.type() in (QEvent.MouseButtonPress, QEvent.MouseButtonDblClick):
                return event.button() == Qt.LeftButton and self.box1.isChecked()
        return super().eventFilter(source, event)

    def dothething(self, checked):
        if checked:
            self.box2.setChecked(True)