Question

J'ai une liste de chaînes et que vous souhaitez créer une entrée de menu pour chacune de ces chaînes. Lorsque l'utilisateur clique sur l'une des entrées, toujours la même fonction doit être appelée avec la chaîne comme argument. Après quelques recherches et d'essayer, je suis venu avec quelque chose comme ceci:

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

Maintenant, le problème est que chacun des éléments du menu imprimer la même sortie: « Article 3 » au lieu de celui correspondant. Je suis reconnaissant pour toutes les idées sur la façon dont je peux obtenir ce droit. Merci.

Était-ce utile?

La solution

Vous vous réunissez ce qui a été souvent appelé (peut-être pas tout à fait pédante-correctement ;-) comme le « problème de cadrage » en Python - la liaison est en retard (recherche lexicale à l'appel-temps) pendant que vous souhaitez qu'il début (à temps def). Alors, où vous avez maintenant:

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

essayer la place:

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

« prévoit » la liaison, car les valeurs par défaut (comme le item un ici) se calcule une fois que pour tous à temps def. Ajout d'un niveau de fonction d'imbrication (par exemple une double lambda) fonctionne aussi, mais il est un peu un surpuissant ici -)

Vous pouvez également utiliser functools.partial(self.doStuff, item) (avec un import functools en haut bien sûr) qui est une autre solution bien, mais je pense que je vais le plus simple (et la plus courante) « faux-valeur par défaut pour argument » langage.

Autres conseils

Cela devrait fonctionner, mais je suis sûr qu'il y avait une meilleure façon que je ne me souviens pas en ce moment.

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

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

Modifier : version plus courte, qui est toujours pas ce que je pense à ... ou peut-être il était dans une autre langue? :)

(lambda x: lambda self.do_stuff(x))(item)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top