更新以添加示例并修剪部分内容。 (请重新打开?)
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中导致的事件序列:MouseButtonPress
,Close
,Hide
,HideToParent
,Enter
,{{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.Close
或MouseReleaseEvent
,它启动了事件链,它恰好归因于{{MousePressEvent
的位置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是一个正确的想法。