2009-09-23 11 views
6

Devo essere in grado di sapere quale elemento ho cliccato in un sistema di menu generato dinamicamente. Voglio solo sapere su cosa ho cliccato, anche se si tratta semplicemente di una rappresentazione di stringa.Pyqt - QMenu popolato e cliccato dinamicamente

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 

risposta

11

Invece di usare onFilmSet direttamente come il destinatario della vostra connessione, utilizzare una funzione lambda in modo da poter passare parametri aggiuntivi:

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

esattamente quello che stavo cercando, ahhh dolce lambda! – crackerbunny

1

Date un'occhiata al sistema di proprietà del Qt. Puoi aggiungere dinamicamente una proprietà contenente una stringa o qualsiasi cosa desideri, che definisce l'azione. Quindi è possibile utilizzare il metodo sender() nello slot per ottenere il QObject che chiama lo slot. Quindi, interrogare la proprietà impostata e fare ciò che si desidera di conseguenza.

Ma questo non è il metodo migliore per farlo. L'uso di mittente() non è consigliato perché viola il principio di modularità orientato agli oggetti.

Il metodo migliore sarebbe utilizzare la classe QSignalMapper. Questa classe mappa i segnali da oggetti diversi nello stesso slot con argomenti diversi.

Non ho usato PyQt quindi non posso darvi una sintassi esatta o un esempio, ma non dovrebbe essere difficile da trovare con una piccola ricerca.

+0

Sono d'accordo che questo sembra il posto dove usare un signal mapper –

1

Stavo cercando di capire un problema simile e dopo aver visto il codice sopra questo è ciò che ha funzionato per me. Ho pensato che sarebbe stato bello mostrarlo tutto insieme. =)

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

Solo alcune informazioni aggiuntive, io non so perché, ma la funzione lambda non funziona con nuova sintassi per i collegamenti PyQt:

Esempio di codice non lavora:

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

Ma se si Subsitute l'ultima riga con la sintassi vecchia connessione stile:

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

Tutto va bene. Con la nuova sintassi di connessione, si ottiene solo l'ultimo elemento del loop :(

+0

Per me (Qt4) funziona anche con la nuova sintassi della connessione, vedi il mio commento a questa risposta: http://stackoverflow.com/a/1102089/3224008 – Leistungsabfall

1

ho trovato this risposta qui per affrontare questo problema in PyQt5, python3. Non mi piace, la variabile BVAL per la precisione , come non capisco completamente, ma c'è voluto molto tempo per trovare così ho pensato di condividerle qui. il BVAL preleva il valore booleano da scatenato e permette al TaskType da passare.

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

Non è necessario passare 'bVal' a' setTask', in modo da liberarsi di quel brutto 'ignore_bVal'. L'unico requisito è inserire un argomento iniziale in 'lambda' in modo che l'argomento' taskType' non venga sovrascritto con il valore booleano. Una soluzione un po 'più robusta (e più generale) sarebbe quella di sostituire 'bVal' con' * args' - che ignorerebbe * tutti i possibili * valori inviati dal segnale e lascerà intatti gli argomenti delle parole chiave. – ekhumoro

+0

Grazie a questa risposta sono riuscito a risolvere un problema simile con Python3 e PyQt5. Questa idea applicata può essere vista anche qui: https: // github.com/Muammar/mkchromecast/commit/719fde94e271f97a2047e84b56d7603a5d8cde09 – muammar