Pyqt dinámica generar acción QMenu y conectar

Sigo aprendiendo cómo funciona pyqt. Quiero generar dinámicamente un customContextMenu y conectarme con una función. ¿Hasta ahora tengo lo siguiente pero la parte de conexión no funciona?

import sys from PyQt4 import QtGui, QtCore class MainForm(QtGui.QMainWindow): def __init__(self, parent=None): super(MainForm, self).__init__(parent) # create button self.button = QtGui.QPushButton("test button", self) self.button.resize(100, 30) # set button context menu policy self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.connect(self.button, QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'), self.on_context_menu) self.popMenu = QtGui.QMenu(self) def on_context_menu(self, point): self.popMenu.clear() #some test list for test testItems = ['itemA', 'itemB', 'itemC'] for item in testItems: action = self.btn_selectPyFilterPopMenu.addAction("Selected %s" % item) self.connect(action,QtCore.SIGNAL("triggered()"),self,QtCore.SLOT("printItem('%s')" % item)) self.popMenu.exec_(self.button.mapToGlobal(point)) @pyqtSlot(str) def printItem(self, item): print item def main(): app = QtGui.QApplication(sys.argv) form = MainForm() form.show() app.exec_() if __name__ == '__main__': main() 

Su código es casi correcto. Solo necesita conectar las señales a un lambda con un argumento predeterminado, como este:

  for item in testItems: action = self.popMenu.addAction('Selected %s' % item) action.triggered[()].connect( lambda item=item: self.printItem(item)) 

El argumento predeterminado garantiza que cada lambda obtenga una copia de la variable de bucle actual . También tenga en cuenta que se utiliza una tupla vacía para especificar la señal triggered . Si esto no se hiciera, la señal triggered enviaría un valor booleano de forma predeterminada, lo que eliminaría el argumento del item de la lambda .

Finalmente, insto a utilizar la syntax de nuevo estilo al conectar señales: el estilo antiguo puede ser muy propenso a errores y es mucho menos python.

Si te entiendo bien:

 import sys from PyQt4 import QtGui, QtCore class MainForm(QtGui.QMainWindow): def __init__(self, parent=None): super(MainForm, self).__init__(parent) # create button self.button = QtGui.QPushButton("test button", self) self.button.resize(100, 30) # set button context menu policy self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.customContextMenuRequested.connect (self.on_context_menu) def on_context_menu(self, point): popMenu = QtGui.QMenu(self) #some test list for test testItems = ['itemA', 'itemB', 'itemC'] # for item in testItems: action = QtGui.Action(item) action.triggered.connect(lambda x: print item) popMenu.exec_(self.button.mapToGlobal(point)) 

Probé y corregí el ejemplo dado en la primera publicación. Aquí está una versión de trabajo. Haga clic derecho en el botón, seleccione un artículo y se imprimirá en su terminal:

 import sys from PyQt4 import QtGui, QtCore class MainForm(QtGui.QMainWindow): def __init__(self, parent=None): super(MainForm, self).__init__(parent) # create button self.button = QtGui.QPushButton("test button",self) self.button.resize(100, 30) # set button context menu policy self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.connect(self.button, QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'), self.on_context_menu) self.popMenu = QtGui.QMenu(self) def on_context_menu(self, point): self.popMenu.clear() #some test list for test testItems = ['itemA', 'itemB', 'itemC'] for item in testItems: action = self.popMenu.addAction('Selected %s' % item) action.triggered[()].connect( lambda item=item: self.printItem(item)) self.popMenu.exec_(self.button.mapToGlobal(point)) @QtCore.pyqtSlot(str) def printItem(self, item): print item def main(): app = QtGui.QApplication(sys.argv) form = MainForm() form.show() app.exec_() if __name__ == '__main__': main()