2009-06-30 6 views
2

Ich versuche, die Menge der Signale zu reduzieren, die ich in meinem Kontextmenüs verwenden muss. Das Menü besteht aus Aktionen, die den Betriebsmodus des Programms wechseln, so dass die von den Slots durchgeführte Operation sehr einfach ist. Unter Angabe die Dokumentation auf QMenu :: ausgelöst,PyQt: Konsolidierung von Signalen zu einem einzelnen Steckplatz

Normalerweise verbinden Sie jede ausgelöst Menü Aktion() Signal an seinen eigenen benutzerdefinierten Slot, aber manchmal werden Sie mehrere Aktionen auf einen einzigen Schlitz zu verbinden, zum Beispiel, wenn Sie haben eine Gruppe eng verbundener Aktionen, wie "linksbündig", "zentriert", "rechtsbündig".

Allerdings kann ich nicht herausfinden, wie dies zu erreichen ist, und die Dokumentation geht nicht weiter ins Detail.
Angenommen, ich habe die Aktionen actionOpMode1 und actionOpMode2 im Menü actionMenu und einen Steckplatz setOpMode. Ich möchte setOpMode mit einem Parameter aufgerufen werden, der sich irgendwie darauf bezieht, welche der Aktionen ausgelöst wurde. Ich habe versucht, verschiedene Permutationen zu diesem Thema:

QObject.connect(self.actionMenu, SIGNAL('triggered(QAction)'), self.setOpMode) 

Aber ich habe noch nie es setOpMode zu nennen, was darauf hindeutet, dass actionMenu nie „fühlt ausgelöst“, sozusagen.

In this SO question, wird es vorgeschlagen, dass es mit lamdbas getan werden kann, aber dies:

QObject.connect(self.actionOpMode1, SIGNAL('triggered()'), lambda t: self.setOpMode(t)) 

gibt "<lambda>() takes exactly 1 argument (0 given)". Ich kann nicht sagen, dass ich wirklich verstehe, wie das funktionieren soll, also habe ich möglicherweise etwas falsch gemacht, wenn ich von clicked() zu triggered() gehe.

Wie wird es gemacht?

Antwort

4

Mit QObject.Sender eine der Lösung ist, wenn auch nicht das sauberste.

Verwenden QSignalMapper zuzuordnen sauber Wert mit dem Objekt, das das Signal ausgesendet.

+0

+1, QSignalMapper ist für diesen Zweck _exactly_ entworfen (und auch ziemlich elegant, denke ich), so bietet es die architektonische Lösung. –

+0

-1 Verwenden Sie QSignalMapper nicht in Python, da ist keine Notwendigkeit. –

1

Sie können QObject::sender() verwenden, um herauszufinden, welche QAction das Signal ausgegeben hat.

Also Ihr Schlitz könnte wie folgt aussehen:

def triggered(self): 
    sender = QtCore.QObject.sender() 

    if sender == self.actionOpMode1: 
     # do something 
    elif sender == self.actionOpMode2: 
     # do something else 

Bezüglich dem, was SO in den anderen los ist Frage, die Sie mit dem Lambda erwähnt, was sie tut, ist eine Lambda mit einem Parameter erstellen, die so einen Standardwert hat

self.connect(self.actionOpMode1, QtCore.SIGNAL('triggered()'), lambda who="mode1": self.changeMode(who)) 
self.connect(self.actionOpMode2, QtCore.SIGNAL('triggered()'), lambda who="mode2": self.changeMode(who)) 

Und dann eine Member-Funktion wie diese haben: dass auf Ihrem Beispiel anwenden würden Sie so etwas wie dies zu tun, müssen

def changeMode(self, who): 
    if who == "mode1": 
     # ... 
    elif who == "mode2": 
     # ... 

Persönlich sieht die erste Annäherung sauberer und lesbarer für mich aus.

+1

connect() erhöht den Refcount des Empfängers nicht; Sie können Lambda in Verbindungen nur verwenden, wenn Sie eine zusätzliche Referenz besitzen. –

2

Ich benutze diesen Ansatz:

from functools import partial 

def bind(self, action, *params): 
    self.connect(action, QtCore.SIGNAL('triggered()'), 
       partial(action, *params, self.onMenuAction)) 

def onMenuAction(self, *args): 
    pass 


bind(self.actionOpMode1, 'action1') 
bind(self.actionOpMode2, 'action2') 
Verwandte Themen