2009-09-23 5 views
6

Je dois être capable de savoir quel élément j'ai cliqué dans un système de menu généré dynamiquement. Je veux seulement savoir sur quoi j'ai cliqué, même s'il s'agit simplement d'une représentation sous forme de chaîne.Pyqt - QMenu dynamiquement peuplé et cliqué

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 

Répondre

11

Au lieu d'utiliser onFilmSet directement le récepteur de votre connexion, utilisez une fonction lambda afin que vous puissiez passer des paramètres supplémentaires:

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

exactement ce que je cherchais, ahhh sweet lambda! – crackerbunny

1

Jetez un coup d'oeil au système de propriété de Qt. Vous pouvez ajouter dynamiquement une propriété contenant une chaîne ou tout ce que vous désirez, ce qui définit l'action. Vous pouvez ensuite utiliser la méthode expéditeur() dans l'emplacement pour obtenir l'objet appelant QObject. Ensuite, interrogez la propriété que vous avez définie et faites ce que vous voulez en conséquence.

Mais, ce n'est pas la meilleure méthode pour le faire. L'utilisation de sender() est déconseillée car elle viole le principe de modularité orienté objet.

La meilleure méthode serait d'utiliser la classe QSignalMapper. Cette classe mappe des signaux provenant d'objets différents vers le même emplacement avec des arguments différents.

Je n'ai pas utilisé PyQt donc je ne peux pas vous donner une syntaxe exacte ou un exemple, mais il ne devrait pas être difficile à trouver avec un peu de recherche.

+0

Je suis d'accord que cela semble être l'endroit pour utiliser un mapper de signal –

1

J'essayais de comprendre un problème similaire et après avoir regardé le code ci-dessus, c'est ce qui a fonctionné pour moi. Je pensais que ce serait bien de tout montrer ensemble. =)

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

Juste quelques informations supplémentaires, Je ne sais pas pourquoi, mais la fonction lambda ne fonctionne pas avec la nouvelle syntaxe PyQt pour les connexions:

Exemple code ne fonctionne pas:

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

Mais si vous Substitut la dernière ligne avec l'ancienne connexion de style syntaxe:

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

Tout va bien. Avec la nouvelle syntaxe de connexion, vous obtenez seulement le dernier élément de la boucle :(

+0

Pour moi (Qt4), il fonctionne également avec la nouvelle syntaxe de connexion, voir mon commentaire à cette réponse: http://stackoverflow.com/a/1102089/3224008 – Leistungsabfall

1

J'ai trouvé this réponse ici pour traiter cette question dans PyQt5, python3. Je ne l'aime pas, la variable bVal pour être précis , que je ne comprends pas bien, mais il a fallu beaucoup de temps pour trouver ce que je pensais que je partagerais ici. le bVal prend la valeur booléenne de déclenchement et permet à l'TaskType à passer.

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

Vous n'avez pas besoin de passer 'bVal' à' setTask', donc vous pouvez vous débarrasser de ce laid 'ignore_bVal'. La seule exigence est que vous insériez un argument initial dans 'lambda' de sorte que l'argument' taskType' ne soit pas écrasé par la valeur booléenne. Une solution légèrement plus robuste (et plus générale) consisterait à remplacer 'bVal' par' * args' - ce qui ignorerait alors * toutes les valeurs possibles * envoyées par le signal, et laisserait les arguments du mot clé intacts. – ekhumoro

+0

J'ai été capable de résoudre un problème similaire avec Python3 et PyQt5 grâce à cette réponse. Cette idée appliquée peut également être vue ici: https: // github.com/muammar/mkchromecast/commit/719fde94e271f97a2047e84b56d7603a5d8cde09 – muammar