阻止PyQt的QActions自动触发

时间:2013-12-24 21:06:19

标签: python qt qt4 pyqt pyqt4

修改

更新以添加示例并修剪部分内容。 (请重新打开?)

Python的Qt实现,PyQt,一直很好,但它的各个方面仍然让我很困惑。

现在我有一个问题,默认情况下会从我不想要的事情中触发事件,并且无法区分我想要触发它的事情和我不想要的事情。

我正在构建一个上下文菜单,当您单击现有操作时,该菜单会在其中弹出新操作。这里以伪代码为例:

from PyQt4 import QtGui,QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.menubar = QtGui.QMenuBar(self)
        self.setMenuBar(self.menubar)
        self.menu = MyMenu(self)
        self.menubar.addAction(self.menu.menuAction())
        self.menu.setTitle('Menu')
        self.listy = []
        self.installEventFilter(self.eventFilter)

class MyMenu(QtGui.QMenu):
    def __init__(self,parent=None):
        QtGui.QMenu.__init__(self)
        self.quit_action = QtGui.QAction("Close",self)
        self.add_action = QtGui.QAction("Add action",self)
        self.new_action = QtGui.QAction(" New action",self)
        self.new_action.setVisible(False)
        self.add_action.triggered.connect(self.toggleActionOn)
        for i in self.quit_action,self.add_action,self.new_action:
            self.addAction(i)
        self.installEventFilter(self)
    def toggleActionOn(self):
        self.new_action.setVisible(True)

除了我已经出现竞争条件之外,它的效果非常好:每当我点击某个动作时,菜单会自动关闭。由于这些内置触发器妨碍了我自己的触发器,我想阻止它们发生。

我试图拦截关闭和鼠标释放事件:

class MyMenu(QtGui.QMenu):
    def closeEvent(self,event):
        ...
        event.accept()
    ...
    def mouseReleaseEvent(self,event):
        ...
        event.accept()
    ...

...这似乎没用,因为收到的事件没有关于发件人的信息。但它告诉我点击在QMenu中导致的事件序列:MouseButtonPressCloseHideHideToParentEnter,{{1 }}

我添加了Leave

eventFilter

给出的'事件'没有任何元素告诉我'关闭'的发件人是什么。

在绝望中,我试图断开行动,class MyMenu(QtGui.QMenu): ... def eventFilter(self, obj, event): print 'EVENT RECEIVED' print obj, event if ( obj is self or obj is self.new_action ) and event.type() == QtCore.QEvent.Close: return True else: return False 和其他类似的非感性伎俩。

有谁知道如何“断开”对象与其相关的“关闭”事件或如何更有选择地禁止关闭事件发生?

更新正如Pavel Strakhov指出的那样,问题在于我对事件处理的误解。要阻止new_action.disconnect(QtCore.QEvent.Close)传递,我必须过滤原始事件QMenu.CloseMouseReleaseEvent,它启动了事件链,它恰好归因于{{MousePressEvent的位置1}}我需要确定。

1 个答案:

答案 0 :(得分:0)

使用截取关闭事件无法阻止关闭菜单。关闭和隐藏在QMenu内部处理。触发操作后,没有任何内容可以阻止QMenu隐藏。

我们应该让QMenu相信行动根本没有被触发。我设法通过过滤MouseButtonRelease事件来做到这一点:

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.menu = None


    def mousePressEvent(self, event):
        menu = QMenu()
        self.menu = menu
        menu.installEventFilter(self)
        self.quit_action = menu.addAction("Close")
        self.add_action = menu.addAction("Add action")
        menu.exec_(self.mapToGlobal(event.pos()))

    def eventFilter(self, obj, event):
        print(obj, self.menu)
        if obj == self.menu:
            if event.type() == QEvent.MouseButtonRelease:
                action = self.menu.actionAt(event.pos())
                if action:
                    if action == self.quit_action:
                        return False
                    elif action == self.add_action:
                        self.menu.addAction("New action")
                        self.menu.exec_()
                        return True
        return False

当用户点击“新操作”时,新项目会立即添加到菜单中而不会隐藏和显示。但是请仔细使用此代码。这应该被视为黑客攻击。无法保证在所有系统上过滤MouseButtonRelease就足够了。使用递归QMenu::exec调用也值得怀疑。

从eventFilter返回True时,将阻止事件并且不会触发QAction,因此不会执行连接的插槽。您需要在eventFilter中手动调用适当的代码(如上面代码中的“add_action”情况所示)。

现在关于你的尝试。 QObject::disconnect功能操作信号和插槽。你不能只是神奇地断开“QtCore.QEvent.Close”与任何东西的连接,因为它不是信号或插槽。这只是一个枚举值。事件不是信号。使用事件过滤器或子类化QMenu是一个正确的想法。