当其他复选框被选中时,将复选框状态更改为未选中(pyqt)

13
我正在使用Qt Designer和pyqt编写应用程序。
我的问题很简单:在我的UI中,我有2个复选框,我需要的是当第二个复选框未选中时,将第一个复选框设置为始终未选中。
换句话说,只有当第二个复选框被选中时,才可以选中第一个复选框,但如果未选中第一个复选框,则仍然可以选中第二个复选框。
在Qt Designer中,我没有找到使用Signals/Slots函数轻松实现此操作的方法。
我查看了Qt API并尝试编写了一些代码:
class CreateRIVLayerDialog(QDialog, FORM_CLASS):
    def __init__(self, iface)

    # some more code here...

    if self.addCheckDB.isChecked():
        self.addCheck.setChecked(False)

但是没有结果。

有人有一些提示吗?

谢谢

3个回答

15

最简单的方法是使用两个信号连接,其中一个可以在Qt Designer中完成。

您的设计要求“只有在勾选第二个复选框时才能勾选第一个复选框”。这相当于说当第二个复选框处于未选中状态时应该使第一个复选框不可用。禁用复选框可以清楚地告诉用户该选项不可用。

因此在Qt Designer中,您应该将checkbox2toggled信号连接到checkbox1setEnabled槽上。(可能还需要在Qt Designer中设置checkbox1的初始enabled状态)。

然后,在您的代码中,您应该进行第二个连接,如下所示:


    self.checkbox2.toggled.connect(
        lambda checked: not checked and self.checkbox1.setChecked(False))

每当取消选中checkbox2时,这将清除checkbox1的选中状态。

如果您想完全使用代码实现,它会像这样:

    self.checkbox1.setEnabled(False)
    self.checkbox2.toggled.connect(self.checkbox1.setEnabled)
    self.checkbox2.toggled.connect(
        lambda checked: not checked and self.checkbox1.setChecked(False))

@ekhmoro。感谢您提供的快速方法!令人惊讶的是,在信号/槽系统中无法轻松更改复选框状态(选中或未选中)。但是,使用您的代码确实可以解决这个问题。 - matteo
@matteo。我觉得这一点并不奇怪。您要求一个小部件的状态以相当特定的方式依赖于另一个小部件。我认为你得到的两个答案表明,PyQt使得实现这一点变得非常容易和合理。 - ekhumoro
从类型的角度来看,setChecked(...)的调用是不正确的...在使用类型时应该小心。Python中没有编译器。因此,如果您正在使用PyQt,有两种方法:查看API的原始签名(https://doc.qt.io/qt-5/qcheckbox.html#setCheckState),或者使用部分准备好的PyQt文档,针对您使用的版本:https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtwidgets/qcheckbox.html。附言:在大型项目中只要没有类型和编译器就会头疼,所以请小心。 - Konstantin Burlachenko

5

只需使用信号。您说得对,无法直接通过设计师来完成,因为您必须反转已选中的属性。我脑海中想到的最简单和最易读的方法是使用公共插槽加上一个内部成员变量来保存两者的选中状态:

  • Add self._toggle = INITIAL_VALUE to your class - the INITIAL_VALUE holds a boolean value, which you use to check/uncheck your checkboxes

      self._toggle = True
      self.check1 = QCheckBox('Check 1', self)
      self.check1.setChecked(self._toggle)
      self.check2 = QCheckBox('Check 2', self)
      self.check2.setChecked(not self._toggle)
    
  • Add a slot:

      @pyqtSlot()
      def toggle(self):
        self._toggle = not self._toggle
        self.check1.setChecked(self._toggle)
        self.check2.setChecked(not self._toggle)
    
  • Connect the clicked signal of both checkboxes to this slot.

    Warning! Do not use the stateChanged signal here or you will start an infinite recursion. :3

      self.check1.clicked.connect(self.toggle)
      self.check2.clicked.connect(self.toggle)
    
我在这里做的基本上是接管两个复选框状态的更改,并手动使用self._toggle的值来操作第一个复选框以及self._toggle的反转值来操作第二个复选框。
如果您希望在插槽中减少反转,以下方法也有效,但在我看来不够易读:
@pyqtSlot()
def toggle(self):
  self.check2.setChecked(self._toggle) # Old value of our check1 becomes the value of check2
  self._toggle = not self._toggle # Invert
  self.check1.setChecked(self._toggle) # New value is assigned to check1

注意: 在槽函数内部也可以使用isChecked(),并且不需要额外的变量就可以完成上述操作。然而,我认为这种方式更易读,并且具有更少的函数调用(每个isChecked()setChecked()都是一个函数调用)。


如果你说的“很多”是指3-4行代码...当然可以。哈哈,你不能省略中间人(插槽),因为你想要一些自定义行为。如果是“每当我选中或取消其中一个复选框时,我想同时选中或取消两个复选框”,那么你就可以直接连接它们的插槽和信号来实现更简单的解决方案。据我所知,在没有额外处理的情况下反转信号的值是不可能的。也许可以用lambda函数实现... - rbaleksandar
如果要同步勾选状态,我认为你可以简单地使用Qt Designer。我会尝试你的代码,再次感谢! - matteo
没问题,如果您有更多的问题、建议等,请随时在这里发表评论。 :) - rbaleksandar

1

我知道我来晚了,但有一种更容易实现的方法,我认为这正是原始作者想要的。如果你有一个名为checkbox_1的复选框,当你勾选/取消它时,它会连接到以下函数。

def Change_the_Checkbox_Function(self):
    if self.checkbox_1.isChecked(): 
        if self.checkbox_2.isChecked():
            pass
        else:
            self.checkbox_2.setChecked(True)
    else:
        self.checkbox_2.setChecked(False)

如果您想让复选框1勾选或取消勾选其他多个复选框(例如全选),则不要直接调用上述函数,而是创建另一个函数来调用其他函数以勾选/取消勾选这些复选框,如下所示:
def Select_ALL_checkboxes(self):
    self.Change_the_Checkbox_1_Function()
    self.Change_the_Checkbox_2_Function()
    self.Change_the_Checkbox_3_Function()

    ....etc

对我来说,这是最合乎逻辑的方式,不会过于技术化。它工作得很好,速度也很快。可能不是最高效或最漂亮的方式,但我发现这是一次性检查/取消多个复选框的最佳方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接