代码之家  ›  专栏  ›  技术社区  ›  Gerald Senarclens de Grancy

从字符串列表创建PyQt菜单

  •  10
  • Gerald Senarclens de Grancy  · 技术社区  · 17 年前

    我有一个字符串列表,希望为每个字符串创建一个菜单项。当用户单击其中一个条目时,应始终使用字符串作为参数调用相同的函数。经过一些尝试和研究,我得出了如下结论:

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

    现在的问题是,每个菜单项将打印相同的输出:“项目3”,而不是相应的一个。我很感激你能给我一些建议,让我把事情做好。谢谢

    2 回复  |  直到 16 年前
        1
  •  25
  •   Alex Martelli    17 年前

    您遇到了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) import functools 这是另一个很好的解决方案,但我想我会选择最简单(也是最常见的)“为参数设置假默认值”的习惯用法。

        2
  •  3
  •   Wojciech Bederski    17 年前

    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)