PyQt - 从字典创建按钮

时间:2011-05-21 20:39:38

标签: python pyqt

我有一本字典 我需要创建带有键名称的按钮,以及基于值的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')

如何让所有按钮的行为不同?

3 个答案:

答案 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_()