Создать меню PyQt из списка строк

У меня есть список строк и я хочу создать пункт меню для каждой из этих строк. Когда пользователь нажимает на одну из записей, всегда должна вызываться одна и та же функция со строкой в качестве аргумента. После некоторых попыток и исследований я придумал что-то вроде этого:

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

Теперь проблема заключается в том, что каждый из пунктов меню будет печатать один и тот же вывод: & quot; Элемент 3 & quot; вместо соответствующего. Я благодарен за любые идеи о том, как я могу сделать это правильно. Благодарю.

Ответы на вопрос(2)

но я уверен, что есть лучший способ, который я не могу вспомнить прямо сейчас.

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)
Решение Вопроса

что часто упоминалось (может быть, не совсем педантически-правильно ;-) как «проблема с областями видимости»; в Python - привязка запаздывает (лексический поиск во время вызова), в то время как вам понравится рано (во время def). Итак, где у вас сейчас есть:

    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 один здесь) вычисляется раз и навсегда в def-time. Добавление одного уровня вложенности функций (например, двойной лямбды) также работает, но это немного излишне! -)

Вы могли бы альтернативно использоватьfunctools.partial(self.doStuff, item) (сimport functools в верхней части), что является еще одним хорошим решением, но я думаю, что я остановлюсь на самом простом (и наиболее распространенном) «поддельном значении по умолчанию для аргумента» идиома.

 02 мая 2016 г., 13:47
Отличный ответ! Он также работает с новым синтаксисом соединения:entry.triggered.connect(lambda item=item: self.doStuff(item))
 09 июл. 2009 г., 10:11
@ Алекс: +1 !!! Это беспокоило меня все утро! лямбда х = х: func (x) FTW :)

Ваш ответ на вопрос