我有一本字典
我需要创建带有键名称的按钮,以及基于值的clicked
插槽:
dic = {'a':'111', 'b':'222', 'c':'333'}
for key in dic:
btn = QPushButton(key, self)
btn.clicked.connect(lambda: doit(dic[key]))
vbox.addWidget(btn)
我有所有正确名称的按钮。最后创建的按钮表现正确。
但所有其他按钮“clicked
”插槽也会连接到上次创建的按钮do('333')
。
如何让所有按钮的行为不同?
答案 0 :(得分:3)
在调用函数之前,匿名函数lambda: doit(dic[key])
不会评估key
。到那时,for-loop
已完成,for-loop
变量key
引用dic
中的最后一个密钥。
当调用匿名函数时(按下按钮时),在全局命名空间中查找key
,并返回当前值key
。
为避免这种陷阱,您可以在lambda
表达式中使用默认参数:
for key in dic:
btn = QPushButton(key, self)
btn.clicked.connect(lambda key=key: doit(dic[key]))
vbox.addWidget(btn)
默认参数在定义时计算,而不是在调用lambda时计算。通过执行此操作,key
在匿名函数的本地命名空间中查找,而不是在全局命名空间中查找,并且因为key的本地命名空间值设置为默认值,对于每次传递,默认值都不同for-loop,您可以获得key
的正确值。
这也在SO answer中解释。
答案 1 :(得分:1)
我认为问题在于,当你调用lambda:doit(dic [key])时,它确实会这样做,并查找dic [key],并且此时key被设置为迭代的最后一项是什么
试试这个:
dic = {'a':'111', 'b':'222', 'c':'333'}
def create_connect(x):
return lambda: doit(x)
for key in dic:
btn = QPushButton(key, self)
btn.clicked.connect(create_connect(dic[key]))
vbox.addWidget(btn)
答案 2 :(得分:1)
你的迭代需要字典dic的键和值。 您可以使用dict.iteritems()方法 如果lambda变得混乱,那么最好使用partial。
试试这个:
from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QPushButton
from functools import partial
class MainWidget(QWidget):
def __init__(self):
super(MainWidget, self).__init__()
dic = {'a':'111', 'b':'222', 'c':'333'}
vbox = QVBoxLayout(self)
for key,val in dic.iteritems():
btn = QPushButton(key, self)
btn.clicked.connect(partial(self.doit, val))
vbox.addWidget(btn)
def doit(self, text):
print "%s" % text
if __name__ == "__main__":
app = QApplication([])
w = MainWidget()
w.show()
app.exec_()