PyQt - 从字典创建按钮

发布于 2024-11-09 02:18:22 字数 381 浏览 0 评论 0原文

我有一本字典。
我需要创建带有键名称的按钮,并根据值创建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')

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

I have a dictionary.
I need to create buttons with keys name, and clicked slot based on value:

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)

I have all buttons with right name. And last created button behave rightly.
But all others buttons' clicked slots are also connected to the last created button do('333').

How can I make all buttons behave differently?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

巷雨优美回忆 2024-11-16 02:18:22

匿名函数 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 循环,您将获得 key 的正确值。

这个SO答案也对此进行了解释。

The anonymous function lambda: doit(dic[key]) does not evaluate key until the function is called. By that time, the for-loop has completed, and the for-loop variable key references the last key in dic.

When the anonymous function is called (when you press a button), key is looked up in the global namespace, and the current value of key is returned.

To avoid this pitfall, you can use a default argument in the lambda expression:

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda key=key: doit(dic[key]))
    vbox.addWidget(btn)

Default arguments are evaluated at definition-time instead of at the time when the lambda is called. By doing this, key is looked up in the local namespace of the anonymous function, rather than in the global namespace, and since the local namespace value for key is set to the default value which is different for each pass through the for-loop, you obtain the right value for key.

This is also explained in this SO answer.

幸福不弃 2024-11-16 02:18:22

我认为问题是,当您调用 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)

I think the problem is that when you call lambda: doit(dic[key]), it does literally that, and looks up dic[key], and at that time key is set to whatever the last item iterated through was

try this:

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)
Smile简单爱 2024-11-16 02:18:22

您的迭代需要字典 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_()

your iteration needs keys and values of dictionary dic.
You can use dict.iteritems() method.
If lambda is getting confusing, then is better to use partial.

Try this:

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_()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文