问题
Still learning how pyqt works. I want to dynamically generate a customContextMenu and connect with a function. So far I got the following but the connect part not working ?
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()
回答1:
Your code is almost right. You just need to connect the signals to a lambda
with a default argument, like this:
for item in testItems:
action = self.popMenu.addAction('Selected %s' % item)
action.triggered.connect(
lambda chk, item=item: self.printItem(item))
The default argument ensures that each lambda
gets a copy of the current loop variable. Also note that an initial chk
argument is also required. This is because the triggered
signal sends its current checked-state (true or false) by default, which would clobber the item
argument of the lambda
.
Finally, I would urge to use the new-style syntax when connecting signals - the old style can be very error-prone, and is far less pythonic.
回答2:
If I understand you right:
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))
回答3:
I tryed and correct the example given in the first post. Here is a working version. Right click on the button, select an item and it will be printed inn your 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()
来源:https://stackoverflow.com/questions/20390323/pyqt-dynamic-generate-qmenu-action-and-connect