2009-09-23 7 views
6

Muszę wiedzieć, jaki element kliknąłem w dynamicznie generowanym menu. Chcę tylko wiedzieć, co kliknąłem, nawet jeśli jest to po prostu ciąg znaków.Pyqt - QMenu dynamicznie wypełnione i kliknięte

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 

Odpowiedz

11

Zamiast onFilmSet bezpośrednio jako odbiorcy połączenia, należy użyć funkcji lambda więc można przekazać dodatkowe parametry:

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

dokładnie to, czego szukałem, ahhh słodka lambda! – crackerbunny

1

Spójrz systemu własności w Qt. Możesz dynamicznie dodać właściwość zawierającą ciąg lub cokolwiek chcesz, co definiuje akcję. Następnie możesz użyć metody sender() w gnieździe, aby uzyskać QObject wywołujący slot. Następnie zapytaj ustawioną właściwość i wykonaj, co chcesz.

Ale to nie jest najlepsza metoda, aby to zrobić. Używanie sendera() nie jest zalecane, ponieważ narusza obiektową zasadę modułowości.

Najlepszą metodą byłoby użycie klasy QSignalMapper. Ta klasa mapuje sygnały z różnych obiektów do tego samego gniazda z różnymi argumentami.

Nie użyłem PyQt, więc nie mogę podać dokładnej składni ani przykładu, ale nie powinno być trudno znaleźć przy odrobinie badań.

+0

Zgadzam się, że to wydaje się być miejscem do użycia mapera sygnału –

1

Próbowałem dowiedzieć się podobny problem i po zapoznaniu się z powyższym kodem jest to, co pracowało dla mnie. Pomyślałem, że dobrze byłoby pokazać to wszystko razem. =)

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

Tylko niektóre dodatkowe informacje, Nie wiem dlaczego, ale funkcja lambda nie działa z nową składnią pyqt dla połączeń:

Przykład kodu nie działa:

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

Ale jeśli subsitute ostatnią linię składni połączenie starego stylu:

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

Wszystko w porządku. Dzięki nowej składni połączenia, można uzyskać tylko ostatni element pętli :(

+0

Dla mnie (Qt4) działa również z nową składnią połączenia, zobacz mój komentarz do tej odpowiedzi: http://stackoverflow.com/a/1102089/3224008 – Leistungsabfall

1

znalazłem this odpowiedź tutaj do czynienia z tym problemem w PyQt5, python3. I nie podoba, zmienna bVal być precyzyjne , bo nie do końca rozumiem to, ale zajęło dużo czasu, aby znaleźć tak myślałem, że to zrobić tutaj. na bVal podnosi wartość logiczną z wyzwalane i pozwala taskType być przekazywane.

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

Nie musisz przekazywać 'bVal' do' setTask', więc możesz pozbyć się tego brzydkiego 'ignore_bVal'. Jedynym wymaganiem jest wstawienie początkowego argumentu w 'lambda', aby argument' taskType' nie został nadpisany wartością boolowską. Nieco bardziej niezawodnym (i bardziej ogólnym) rozwiązaniem byłoby zastąpienie 'bVal' przez' * args' - które zignorowałoby * wszystkie możliwe * wartości wysyłane przez sygnał i pozostawiłoby argumenty słów kluczowych nietknięte. – ekhumoro

+0

Dzięki tej odpowiedzi udało mi się rozwiązać podobny problem z Python3 i PyQt5. Ten pomysł można również zobaczyć tutaj: https: // github.com/muammar/mkchromecast/commit/719fde94e271f97a2047e84b56d7603a5d8cde09 – muammar