从字符串列表创建 PyQt 菜单

发布于 2024-07-26 06:19:47 字数 840 浏览 4 评论 0原文

我有一个字符串列表,想为每个字符串创建一个菜单条目。 当用户单击其中一个条目时,始终应使用字符串作为参数来调用相同的函数。 经过一番尝试和研究,我想出了这样的结果:

import sys
from PyQt4 import QtGui, QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.menubar = self.menuBar()
        menuitems = ["Item 1","Item 2","Item 3"]
        menu = self.menubar.addMenu('&Stuff')
        for item in menuitems:
            entry = menu.addAction(item)
            self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))
            menu.addAction(entry)
        print "init done"

    def doStuff(self, item):
        print item

app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

现在的问题是每个菜单项都会打印相同的输出:“Item 3”而不是相应的输出。 我很感谢您提供有关如何解决此问题的任何想法。 谢谢。

I have a list of strings and want to create a menu entry for each of those strings. When the user clicks on one of the entries, always the same function shall be called with the string as an argument. After some trying and research I came up with something like this:

import sys
from PyQt4 import QtGui, QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.menubar = self.menuBar()
        menuitems = ["Item 1","Item 2","Item 3"]
        menu = self.menubar.addMenu('&Stuff')
        for item in menuitems:
            entry = menu.addAction(item)
            self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))
            menu.addAction(entry)
        print "init done"

    def doStuff(self, item):
        print item

app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

Now the problem is that each of the menu items will print the same output: "Item 3" instead of the corresponding one. I'm thankful for any ideas about how I can get this right. Thanks.

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

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

发布评论

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

评论(2

此岸叶落 2024-08-02 06:19:47

你遇到了Python中经常提到的(也许不完全迂腐正确;-)作为“范围问题”——绑定很晚(在调用时进行词法查找),而你希望它早点(在定义时间)。 因此,您现在可以

    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))

尝试:

    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda item=item: self.doStuff(item))

这会“预测”绑定,因为默认值(如此处的 item 之一)会在默认时间计算一次。 添加一层函数嵌套(例如双 lambda)也可以,但这里有点矫枉过正!-)

您也可以使用 functools.partial(self.doStuff, item) (带有当然,在顶部导入 functools )这是另一个很好的解决方案,但我想我会选择最简单(也是最常见)的“参数的假默认值”习惯用法。

You're meeting what's been often referred to (maybe not entirely pedantically-correctly;-) as the "scoping problem" in Python -- the binding is late (lexical lookup at call-time) while you'd like it early (at def-time). So where you now have:

    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda: self.doStuff(item))

try instead:

    for item in menuitems:
        entry = menu.addAction(item)
        self.connect(entry,QtCore.SIGNAL('triggered()'), lambda item=item: self.doStuff(item))

This "anticipates" the binding, since default values (as the item one here) get computed once an for all at def-time. Adding one level of function nesting (e.g. a double lambda) works too, but it's a bit of an overkill here!-)

You could alternatively use functools.partial(self.doStuff, item) (with an import functools at the top of course) which is another fine solution, but I think I'd go for the simplest (and most common) "fake default-value for argument" idiom.

榆西 2024-08-02 06:19:47

这应该可行,但我很确定有更好的方法,但我现在不记得了。

def do_stuff_caller(self, item):
    return lambda: self.doStuff(item)

...
self.connect(entry, QtCore.SIGNAL('triggered()'), self.do_stuff_caller(item))

编辑
较短的版本,这仍然不是我正在考虑的......或者也许是另一种语言? :)

(lambda x: lambda self.do_stuff(x))(item)

This should work, but I'm pretty sure there was a better way that I can't recall right now.

def do_stuff_caller(self, item):
    return lambda: self.doStuff(item)

...
self.connect(entry, QtCore.SIGNAL('triggered()'), self.do_stuff_caller(item))

Edit:
Shorter version, that still isn't what I'm thinking about... or maybe it was in another language? :)

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