Pyqt - QMenu is dynamically populated and clicked

I need to know which item I clicked in a dynamically created menu system. I just want to know what I clicked on, even if it's just a string representation.

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 
+6
python user-interface qt pyqt
source share
5 answers

Instead of using onFilmSet directly as the recipient of your connection, use the lambda function so that you can pass additional parameters:

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

Take a look at the Qt property system. You can dynamically add a property containing a string or whatever you want that defines an action. Then you can use the sender () method in the slot to get the QObject calling the slot. Then request the property you set and do whatever you want.

But this is not the best way to do this. Using sender () is not recommended because it violates the object-oriented principle of modularity.

The best method would be to use the QSignalMapper class. This class maps signals from different objects to the same slot with different arguments.

I have not used PyQt, so I cannot give you the exact syntax or example, but it is not difficult to find with a little research.

+1
source share

I tried to figure out a similar problem, and by looking at the code above, this is what worked for me. I thought it would be nice to show it all together. =)

 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
source share

Just additional information, I don’t know why, but the lambda function does not work with the new pyqt syntax for connections:

Sample code does not work:

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

But if you sign the last line with the old-style syntax:

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

Everything is good. With the new join syntax, you only get the last element of the loop :(

+1
source share

I found this answer to this question in PyQt5, python3. I don’t like it, the bVal variable is accurate, because I do not quite understand it, but it took a long time to find, so I decided to share it here. BVal takes a boolean value from the launch and allows you to pass the type of task.

 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 
+1
source share

All Articles