Create PyQt menu from a list of strings

后端 未结 2 449
孤城傲影
孤城傲影 2020-12-28 10:15

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

相关标签:
2条回答
  • 2020-12-28 10:40

    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.

    0 讨论(0)
  • 2020-12-28 10:44

    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)
    0 讨论(0)
提交回复
热议问题