【问题标题】:prevent PyQt's QActions from automatic triggers [closed]防止 PyQt 的 QActions 自动触发 [关闭]
【发布时间】:2013-12-24 21:06:18
【问题描述】:

UPDATE 已编辑以添加示例并修剪一些内容。 (请重新打开?)

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 中单击导致的事件顺序:MouseButtonPressCloseHideHideToParentEnterLeave

我添加了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

给出的“事件”没有任何元素告诉我“关闭”的发送者是什么。

在绝望中,我试图断开动作,new_action.disconnect(QtCore.QEvent.Close),以及其他类似的荒谬策略。

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

更新 正如 Pavel Strakhov 指出的那样,问题在于我对事件处理的误解。为了阻止QMenu.Close 通过,我必须过滤原始事件@​​987654333@ 或MousePressEvent,它启动了事件链,它恰好归因于我需要识别的QAction 的位置.

【问题讨论】:

  • 请剪掉文字墙,贴一些实际代码。

标签: python qt qt4 pyqt pyqt4


【解决方案1】:

无法使用拦截关闭事件来阻止关闭菜单。关闭和隐藏在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,所以连接的slot不会被执行。您需要在 eventFilter 中手动调用相应的代码(如上面代码中的“add_action”案例所示)。

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

【讨论】:

  • 非常好。您已经指出了我在狭隘视野中错过的内容:close() 附加到正在关闭的对象上,仅此而已; MouseButtonRelease 和其他“鼠标”事件与被单击对象相关的位置相关联。我修改了一些东西,不确定它们是否重要:在MainWindow 对象上附加了一个永久菜单,而不是在每次点击时创建一个新菜单,还使用menu.popup() 而不是menu.exec_()。我知道我尝试disconnect 的大部分事情没有意义,但我很绝望。
猜你喜欢
  • 2012-12-31
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多