2009-09-23 8 views
6

Ich muss in der Lage sein zu wissen, welches Element ich in einem dynamisch generierten Menüsystem angeklickt habe. Ich möchte nur wissen, auf was ich geklickt habe, auch wenn es nur eine String-Darstellung ist.Pyqt - QMenu dynamisch gefüllt und geklickt

def populateShotInfoMenus(self): 
    self.menuFilms = QMenu() 
    films = self.getList() 

    for film in films: 
     menuItem_Film = self.menuFilms.addAction(film) 
     self.connect(menuItem_Film, SIGNAL('triggered()'), self.onFilmSet) 
     self.menuFilms.addAction(menuItem_Film) 

def onFilmRightClick(self, value): 
    self.menuFilms.exec_(self.group1_inputFilm.mapToGlobal(value)) 

def onFilmSet(self, value): 
    print 'Menu Clicked ', value 

Antwort

11

Statt onFilmSet direkt als Empfänger Ihrer Verbindung zu verwenden, verwenden Sie eine Lambda-Funktion, so dass Sie zusätzliche Parameter übergeben können:

receiver = lambda film=film: self.onFilmSet(self, film) 
self.connect(menuItem_Film, SIGNAL('triggered()'), receiver) 
+0

genau das, was ich suchte, ahhh süße Lambda! – crackerbunny

1

Werfen Sie einen Blick auf das Eigenschaftensystem von Qt. Sie können dynamisch eine Eigenschaft hinzufügen, die eine Zeichenfolge oder einen beliebigen Inhalt enthält, der die Aktion definiert. Dann können Sie die Methode sender() im Slot verwenden, um das QObject zu erhalten, das den Slot aufruft. Fragen Sie dann die von Ihnen festgelegte Eigenschaft ab und tun Sie, was Sie wollen.

Aber das ist nicht die beste Methode, dies zu tun. Die Verwendung von sender() wird nicht empfohlen, da es das objektorientierte Prinzip der Modularität verletzt.

Die beste Methode wäre die Verwendung der QSignalMapper-Klasse. Diese Klasse bildet Signale von verschiedenen Objekten auf denselben Slot mit unterschiedlichen Argumenten ab.

Ich habe PyQt nicht verwendet deshalb kann ich Ihnen nicht genaue Syntax oder ein Beispiel geben, aber es sollte nicht schwer sein, mit ein wenig Forschung zu finden.

+0

Ich stimme zu, dass dies scheint der Ort, um eine Signal-Mapper zu verwenden. –

1

Ich habe versucht, ein ähnliches Problem herauszufinden und nach dem Blick auf den obigen Code ist das, was für mich arbeitete. Ich dachte, es wäre gut, alles zusammen zu zeigen. =)

self.taskMenu = QtGui.QMenu("Task") 
self.tasks = self.getTasks() #FETCHES A LIST OF LIST 
self.menuTasks = QtGui.QMenu() 
for item in self.tasks: 
    menuItem_Task = self.taskMenu.addAction(item[1]) 
    receiver = lambda taskType=item[0]: self.setTask(taskType) 
    self.connect(menuItem_Task, QtCore.SIGNAL('triggered()'), receiver) 
    self.taskMenu.addAction(menuItem_Task) 

def setTask(self,taskType): 
    print taskType 
1

Nur einige zusätzliche Informationen, Ich weiß nicht, warum, aber Lambda-Funktion funktioniert nicht mit neuen pyqt Syntax für Verbindungen:

Beispiel Code nicht funktioniert:

self.contextTreeMenuAssignTo = QtGui.QMenu(self) 
    actionAssign = contextMenu.addMenu(self.contextTreeMenuAssignTo) 
    actionAssign.setText("Assign to : ") 
    for user in self.whoCanBeAssignated() : 
     actionAssignTo = QtGui.QAction(user[0] ,self) 
     self.contextTreeMenuAssignTo.addAction(actionAssignTo) 
     actionAssignTo.triggered.connect( lambda userID = user[1] : self.assignAllTo(userID) ) 

Aber wenn Sie subsitute die letzte Zeile mit der alten Stil Verbindung Syntax:

self.connect(actionAssignTo, QtCore.SIGNAL('triggered()'), lambda userID = user[1] : self.assignAllTo(userID) )  

Alles ist in Ordnung. Mit der neuen Verbindung Syntax, nur das letzte Element der Schleife erhalten :(

+0

Für mich (Qt4) funktioniert es auch mit der neuen Verbindungssyntax, siehe meinen Kommentar zu dieser Antwort: http://stackoverflow.com/a/1102089/3224008 – Leistungsabfall

1

ich für den Umgang mit diesem Problem in PyQt5 this Antwort hier, python3. Ich mag es nicht, die bVal Variable genau zu sein , wie ich sie verstehe nicht ganz, aber es dauerte eine lange Zeit dachte ich, zu finden, so würde ich es hier teilen. die bVal abholt den booleschen Wert von ausgelöst und ermöglicht es dem Tasktype übergeben werden.

self.taskMenu = QtGui.QMenu("Task") 
self.tasks = self.getTasks() #FETCHES A LIST OF LIST 
self.menuTasks = QtGui.QMenu() 

for item in self.tasks: 
    menuItem_Task = self.taskMenu.addAction(item[1]) 
    receiver = lambda: bVal, taskType=item: self.setTask(bVal, taskType) 
    menuItem_Task.triggered.connect(receiver) 
    self.taskMenu.addAction(menuItem_Task) 

def setTask(self, ignore_bVal, taskType): 
    print taskType 
+0

Sie müssen 'bVal' nicht an' setTask' übergeben, damit Sie dieses hässliche 'ignore_bVal' loswerden können. Die einzige Voraussetzung ist, dass Sie ein Anfangsargument in das "Lambda" einfügen, so dass das 'taskType'-Argument nicht mit dem booleschen Wert überschrieben wird. Eine etwas robustere (und allgemeinere) Lösung bestünde darin, "bVal" durch "* args" zu ersetzen, was dann alle möglichen * Werte ignoriert, die vom Signal gesendet werden, und die Schlüsselwortargumente unberührt lassen. – ekhumoro

+0

Ich konnte ein ähnliches Problem mit Python3 und PyQt5 dank dieser Antwort lösen. Diese Idee findet sich auch hier: https: // github.com/muammar/mkchromecast/commit/719fde94e271f97a2047e84b56d7603a5d8cde09 – muammar