0

I want to populate a menu dynamically with pyqt5. I am looping all actions and adding them in one by one, this does populate the menu just right, however, all the actions are connected to the last slot function. So even if I select item 1, the console print is item 3. Below is a snippet of my code:

menu = QMenu()
items = ['item 1', 'item 2', 'item 3']
for item in items:
    self.menu.addAction(item, lambda: self.printMe(item))

def printMe(self, text):
    print(text, "selected")
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Ijlal
  • 159
  • 2
  • 13
  • Possible duplicate of [Scope of lambda functions and their parameters?](https://stackoverflow.com/questions/938429/scope-of-lambda-functions-and-their-parameters). See also: https://stackoverflow.com/questions/4578861/connecting-slots-and-signals-in-pyqt4-in-a-loop and https://stackoverflow.com/questions/19837486/python-lambda-in-a-loop, etc, etc... – ekhumoro Mar 26 '18 at 18:10
  • Does this answer your question? [Creating functions (or lambdas) in a loop (or comprehension)](https://stackoverflow.com/questions/3431676/creating-functions-or-lambdas-in-a-loop-or-comprehension) – Karl Knechtel Aug 19 '22 at 03:43

2 Answers2

0

so I found out that if instead of the lambda if we use partials then the code works fine.

self.menu.addAction(item, functools.partial(self.printMe, item))
Ijlal
  • 159
  • 2
  • 13
0

One solution to this is to use a dictionary instead of a list, and define the lambda functions as the value. This way the lambda functions are stored and can be correctly accessed later.

menu = QtWidgets.QMenu()
items = {'item 1': lambda: self.printMe('item 1'), 
         'item 2': lambda: self.printMe('item 2'), 
         'item 3': lambda: self.printMe('item 3')}
for key, value in items.items():
    menu.addAction(key, value)

This method becomes more useful when you need to supply something other than the text of the menu item as an argument.

MalloyDelacroix
  • 2,193
  • 1
  • 13
  • 17