Create PyQt menu from a list of strings

与世无争的帅哥 提交于 2019-11-30 00:47:17

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.

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!