我有一个包含QWidget
的课程QLabel
。该课程在QCheckbox
中生成QVBox
个。我正在尝试将每个复选框连接到方法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()
我找到了几个" hack"的解决方案。
解决方案1:创建一个callBack函数可以解决问题:
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?这里发生了什么?
答案 0 :(得分:2)
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())