pyqt动态生成QMenu动作并连接

时间:2013-12-05 02:35:50

标签: python pyqt4

还在学习pyqt的工作原理。我想动态生成customContextMenu并与函数连接。到目前为止,我得到以下内容,但连接部分无法正常工作?

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()

3 个答案:

答案 0 :(得分:14)

您的代码几乎是正确的。您只需要使用默认参数将信号连接到lambda,如下所示:

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

默认参数确保每个lambda获取当前循环变量的副本。另请注意,空元组用于指定triggered信号。如果没有这样做,triggered信号默认会发送一个布尔值,这会破坏item的{​​{1}}参数。

最后,我希望在连接信号时使用new-style syntax - 旧样式可能非常容易出错,并且远不如pythonic。

答案 1 :(得分:1)

如果我理解你的话:

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))

答案 2 :(得分:1)

我尝试并纠正了第一篇文章中给出的例子。这是一个工作版本。 右键单击按钮,选择一个项目,它将打印在您的终端中:

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()