PyQt - QMenu povoada de forma dinâmica e clicado
-
13-09-2019 - |
Pergunta
Eu preciso ser capaz de saber o item I clicou em um sistema de menu gerado dinamicamente. Eu só quero saber o que eu clicado, mesmo que seja simplesmente uma representação de cadeia.
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
Solução
Em vez de usar onFilmSet
diretamente como o receptor de sua conexão, use uma função lambda para que possa passar parâmetros adicionais:
receiver = lambda film=film: self.onFilmSet(self, film)
self.connect(menuItem_Film, SIGNAL('triggered()'), receiver)
Outras dicas
Dê uma olhada em sistema de propriedade do Qt. Você pode adicionar dinamicamente uma propriedade que contém uma string ou qualquer coisa que você deseja, que define a ação. Então você pode usar o método remetente () na ranhura para obter o QObject chamando o slot. Em seguida, consulta a propriedade você definir e fazer o que quiser em conformidade.
Mas, este não é o melhor método para fazer isso. Usando remetente () não é aconselhável, porque viola o princípio de objeto orientado de modularidade.
O melhor método seria usar classe QSignalMapper. Esta classe mapeia sinais de diferentes objetos para o mesmo slot com argumentos diferentes.
Eu não usei PyQt, portanto, eu não posso dar-lhe sintaxe exata ou um exemplo, mas não deve ser difícil de encontrar com um pouco de pesquisa.
Eu estava tentando descobrir um problema semelhante e depois de olhar para o código acima isto é o que funcionou para mim. Pensei que seria bom para mostrar-lo todos juntos. =)
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
Apenas algumas informações adicionais, Eu não sei por que, mas a função lambda não funciona com nova sintaxe PyQt para conexões:
Exemplo de código não funciona:
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 ) )
Mas se você subsitute a última linha com a sintaxe antiga conexão estilo:
self.connect(actionAssignTo, QtCore.SIGNAL('triggered()'), lambda userID = user[1] : self.assignAllTo( userID ) )
Está tudo bem. Com a nova sintaxe de conexão, você só obter o último elemento do loop: (
este responder aqui para lidar com esta questão em PyQt5, python3. Eu não gosto disso, a variável bVal para ser mais preciso, como eu não entendo totalmente, mas levou muito tempo para encontrar, então eu pensei que eu iria partilhá-la aqui. O bVal pega o valor booleano de acionado e permite que o TaskType a ser passado.
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