Pyqt - QMenu динамически заполняется и нажимается
-
13-09-2019 - |
Вопрос
Мне нужно иметь возможность знать, на какой элемент я нажал в динамически генерируемой системе меню.Я только хочу знать, на что я нажал, даже если это просто строковое представление.
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
Решение
Вместо того, чтобы использовать onFilmSet
непосредственно в качестве получателя вашего соединения используйте лямбда-функцию, чтобы вы могли передавать дополнительные параметры:
receiver = lambda film=film: self.onFilmSet(self, film)
self.connect(menuItem_Film, SIGNAL('triggered()'), receiver)
Другие советы
Взгляните на систему свойств Qt.Вы можете динамически добавлять свойство, содержащее строку или что угодно по вашему желанию, которое определяет действие.Затем вы можете использовать метод sender() в слоте, чтобы получить QObject, вызывающий слот.Затем запросите заданное вами свойство и делайте соответственно все, что хотите.
Но это не лучший способ сделать это.Использовать sender() не рекомендуется, поскольку это нарушает объектно-ориентированный принцип модульности.
Лучшим методом было бы использование класса QSignalMapper.Этот класс отображает сигналы от разных объектов в один и тот же слот с разными аргументами.
Я не использовал PyQt, поэтому не могу привести вам точный синтаксис или пример, но его не должно быть трудно найти при небольшом исследовании.
Я пытался разобраться с аналогичной проблемой, и после просмотра приведенного выше кода это то, что сработало у меня.Подумал, что было бы неплохо показать все это вместе.=)
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
Просто немного дополнительной информации, Я не знаю почему, но лямбда-функция не работает с новым синтаксисом pyqt для соединений :
Пример кода, который не работает :
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 ) )
Но если вы замените последнюю строку синтаксисом соединения в старом стиле :
self.connect(actionAssignTo, QtCore.SIGNAL('triggered()'), lambda userID = user[1] : self.assignAllTo( userID ) )
Все в порядке.С новым синтаксисом подключения вы получаете только последний элемент цикла :(
Я нашел это ответьте здесь за решение этой проблемы в PyQt5, python3.Мне это не нравится, точнее, переменная BVal, поскольку я не до конца понимаю ее, но на поиск ушло много времени, поэтому я решил поделиться ею здесь.BVal выбирает логическое значение из triggered и разрешает передачу TaskType .
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