I'm trying to create a number of context menu items inside a loop. Each of them has its own name and should be connected to a specific function (when clicked). I found that if I write something like:
from PyQt5 import QtCore, QtWidgets, QtSvg
from PyQt5.QtGui import *
import sys
class MyMainWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 500, 500)
self.show()
def myMenuHandler(self, name):
print('from', name)
def contextMenuEvent(self, event):
menu = QtWidgets.QMenu(self)
# Method 1
action = QtWidgets.QAction('outside1', menu)
action.triggered.connect(lambda: self.myMenuHandler('outside1'))
menu.addAction(action)
action = QtWidgets.QAction('outside2', menu)
action.triggered.connect(lambda: self.myMenuHandler('outside2'))
menu.addAction(action)
# Method 2
for s in ['item1', 'item2', 'item3']:
action = QtWidgets.QAction(s, menu)
action.triggered.connect(lambda: self.myMenuHandler(s))
menu.addAction(action)
action = menu.exec_(self.mapToGlobal(event.pos()))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
widget = MyMainWidget()
sys.exit(app.exec_())
Then There are five items when I right click on the widget, when I click them in order:
What I expected from the output:
from outside1
from outside1
from item1
from item2
from item3
Actual output:
from outside1
from outside2
from item3
from item3
from item3
Notice that whatever item I clicked on the actions created inside the for
loop, they all triggered the last item.
I inspected the call stack and found that those three outputs were all triggered by item3
, which is exactly the last item created inside the loop.
Why adding an action inside and outside behave differently? Does that have something to do with Python's variable scope or the PyQt5 itself?