pyqt4正确连接QCheckbox状态

Posted

技术标签:

【中文标题】pyqt4正确连接QCheckbox状态【英文标题】:pyqt4 correctly connecting QCheckbox state 【发布时间】:2014-12-24 12:11:51 【问题描述】:

我有一个类QWidget 包含一个QLabel。该类在QVBox 中生成QCheckbox'es。我正在尝试将每个复选框连接到 nameCheckBox 方法,该方法将更新 QLabel 以显示最后一个复选框的标题。但是,当一个复选框被有效地取消/选中时,它总是被检测为未选中。此外,返回的名称始终是最后创建的复选框。我不明白我的错误在哪里。这是我的代码:

import sys
from PyQt4 import QtCore
from PyQt4.QtGui import *
from MenusAndToolbars import MenuWindow

class checkBoxWidget(QWidget):
    """
    This widget has a QVBox which contains a QLabel and QCheckboxes.
    Qcheckbox number is connected to the label.
    """

    def __init__(self):
        QWidget.__init__(self)
        self.__setUI()

    def __setUI(self):
        vbox = QVBoxLayout(self)
        label = QLabel('Last clicked button: ' + "None", self)

        vbox.addWidget(label)

        listCB = []

        for i in range(10):
            listCB.append( QCheckBox('CheckBox Nb. ' + str(i+1) ) )
            listCB[i].stateChanged.connect(lambda: self.nameCheckBox(label,  listCB[i]) )
            vbox.addWidget( listCB[i] )


    def nameCheckBox(self, label, checkBox):
        if checkBox.isChecked():
            print "Checked: " + checkBox.text()
            label.setText('Last clicked button: ' + checkBox.text())
        else:
            print "Unchecked: " + checkBox.text()



def main():
    app = QApplication(sys.argv)
    window = QMainWindow()
    window.setCentralWidget( checkBoxWidget() )
    window.show()
    #window = WidgetWindow()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

编辑 1

我找到了几个“黑客”解决方案。

解决方案 1:创建一个回调函数就可以了:

def callBack(self, list, index, label):
    return lambda: self.nameCheckBox(label, list[index])

然后我这样连接QCheckbox().stateChanged信号:

listCB[i].stateChanged.connect( self.callBack(listCB, i, label) )

解决方案 2:使用 partial 模块:

首先我们导入模块:

from functools import partial

那么信号连接就是这样完成的:

listCB[i].stateChanged.connect( partial( self.nameCheckBox, label, listCB[i] ) )

但是我想在一行中使用 lambda 表达式。特别是我想了解它是如何工作的。以下链接我了解问题与 lambda 范围有关。正如 Oleh Prypin 建议我的那样,我写道:

listCB[i].stateChanged.connect(lambda i=i: self.nameCheckBox(label,  listCB[i]) )

这里的变量i 是一个新变量。但是我原来的问题仍然存在。然后我出于好奇尝试了这个:

listCB[i].stateChanged.connect( lambda label=label, listCB=listCB, i=i: self.nameCheckBox(label, listCB[i] ) )

但我收到以下错误:

Traceback (most recent call last):
Checked: CheckBox Nb. 2
  File "Widgets.py", line 48, in <lambda>
    listCB[i].stateChanged.connect( lambda label=label, listCB=listCB, i=i: self.nameCheckBox(label, listCB[i] ) )
  File "Widgets.py", line 59, in nameCheckBox
    label.setText('Last clicked button: ' + checkBox.text())
AttributeError: 'int' object has no attribute 'setText'

这里似乎在取消/选中时识别出正确的按钮。但是似乎新的label 变量被视为一个int?这里发生了什么?

【问题讨论】:

【参考方案1】:
lambda: self.nameCheckBox(label,  listCB[i])

绑定到变量 i,这意味着 i 的值将是调用 lambda 时的值,而不是创建时的值,在这种情况下,始终为 9。 可能的修复:

lambda i=i: self.nameCheckBox(label, listCB[i])

有很多关于这个主题的一般信息。起点:Google search,另一个问题Creating lambda inside a loop。


不幸的是,我的修复没有奏效,因为该信号为它调用的函数提供了一个参数checked,根据检查状态用 0 或 2 覆盖该默认参数。这将起作用(忽略不需要的参数):

lambda checked, i=i: self.nameCheckBox(label, listCB[i])

这是编写该类的另一种方法:

class CheckBoxWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi()

    def setupUi(self):
        vbox = QVBoxLayout(self)
        self.label = QLabel("Last clicked button: None")

        vbox.addWidget(self.label)

        for i in range(10):
            cb = QCheckBox("CheckBox Nb. " + str(i+1))
            cb.stateChanged.connect(self.nameCheckBox)
            vbox.addWidget(cb)

    def nameCheckBox(self, checked):
        checkBox = self.sender()
        if checked:
            print("Checked: " + checkBox.text())
            self.label.setText("Last clicked button: " + checkBox.text())
        else:
            print("Unchecked: " + checkBox.text())

【讨论】:

谢谢我用回调解决方案和我应该像你写的那样使用的语法编辑了我的帖子,但是它仍然不起作用,也许listCB的范围也有问题? 非常感谢这两种方法都很有效。作为新手,我倾向于忘记sender() 方法,该方法被证明是有用的。我想我必须系统地检查文档中信号返回的值?

以上是关于pyqt4正确连接QCheckbox状态的主要内容,如果未能解决你的问题,请参考以下文章

PyQt4 - QLineEdit() 和 QCheckbox()

使用 pyqt4 创建类信号

在 pyQt4 中 QCheckBox 的 clicked() 和 stateChanged() 信号有啥区别?

将图标移动到 QCheckBox 中文本的右侧

复选框QCheckBox

将QCheckBox的状态保存在文件中,程序重启时加载状态