Domanda

Ho una lista di stringhe e voglio creare una voce di menu per ciascuna di queste stringhe. Quando l'utente clicca su una delle voci, sempre la stessa funzione sarà chiamata con la stringa come argomento. Dopo qualche tentativo e di ricerca mi si avvicinò con qualcosa di simile:

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

Ora il problema è che ciascuno degli elementi del menu stamperà la stessa uscita: "Articolo 3" invece di quello corrispondente. Sono grato per tutte le idee su come posso ottenere questo diritto. Grazie.

È stato utile?

Soluzione

Si sta incontrando ciò che è stato spesso definito (forse non del tutto pedantemente-correttamente ;-) come il "problema scoping" in Python - l'associazione è in ritardo (di ricerca lessicale al call-tempo), mentre ti piacerebbe presto (alle DEF-time). Allora, dove ora avete:

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

provare invece:

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

Questa "anticipa" il legame, in quanto i valori di default (come il item uno qui) vengono calcolati una volta per tutte al DEF-tempo. L'aggiunta di un livello di funzione di nidificazione (ad esempio un doppio lambda) funziona anche, ma è un po 'di un peso inutile qui -!)

Si potrebbe in alternativa utilizzare functools.partial(self.doStuff, item) (con una import functools nella parte superiore del corso), che è un altro bel soluzione, ma penso che mi piacerebbe andare per il più semplice (e più comune) "default-valore falso per argomento" idioma.

Altri suggerimenti

Questo dovrebbe funzionare, ma sono abbastanza sicuro che ci fosse un modo migliore che non riesco a ricordare in questo momento.

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

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

Modifica : versione più breve, che ancora non è quello che sto pensando ... o forse era in un'altra lingua? :)

(lambda x: lambda self.do_stuff(x))(item)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top