2013-12-05 3 views
5

Все еще изучает работу pyqt. Я хочу динамически генерировать customContextMenu и подключаться к функции. До сих пор я получил следующее, но часть подключения не работает?pyqt dynamic генерирует действие QMenu и подключается

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

ответ

12

Ваш код почти сразу. Вам просто нужно подключить сигналы в 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 аргумент lambda.

Наконец, я хотел бы использовать new-style syntax при подключении сигналов - старый стиль может быть очень подвержен ошибкам и намного менее питоничен.

+0

Спасибо, ekhumoro. .. Есть другие решения, размещенные на SO, но они не работают. Вы неоднократно решали многие мои проблемы, и я бы хотел, чтобы я знал вас лично. – panofish

+0

@panofish. Рад, что я смог помочь :) – ekhumoro

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

Как передать значение функции? У меня есть тестовая функция printItem. Мне нужно знать, какой элемент я нажал в динамически сгенерированном меню. Благодаря! – moDong

+0

Если вы хотите создать свой собственный сигнал, вы должны подклассифицировать QAction. Посмотрите: http://stackoverflow.com/a/5153552/1516544 –

+0

рассмотрите использование [QSignalMapper] (http://qt-project.org/doc/qt-4.7/qsignalmapper.html) – Jeannot

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() 
Смежные вопросы