如何从 QGraphicsView 上下文菜单启动 QGraphicsItem 中的上下文菜单事件 - PyQt6
how to initiate context menu event in QGraphicsItem from QGraphicsView context menu - PyQt6
我在 QGraphicsView 上有一个上下文菜单。我无法激活 QTextGraphicsItem 的上下文菜单。我读到我需要向项目发送场景事件,但我找不到使 sendEvent 方法工作所需的事件。
def graphicsview_menu(self, position):
item = self.ui.graphicsView.itemAt(position)
if item is not None:
self.scene.sendEvent(item, event)
return
# Menu for blank graphics view area
menu = QtWidgets.QMenu()
...
如 contextMenuPolicy
文档所述:
The default value of this property is Qt::DefaultContextMenu
, which means the contextMenuEvent()
handler is called. [...] With Qt::CustomContextMenu
, the signal customContextMenuRequested()
is emitted.
这意味着如果您设置自定义策略,图形视图将不会调用contextMenuEvent()
,这实际上允许它最终发送一个新的图形上下文项目的菜单事件,如果它支持的话。
解决方案是在viewport(这是首先实际接收事件的地方)上安装一个事件过滤器,调用基础实现和return event.isAccepted()
的结果表明事件是否已被处理(可能显示菜单的项目)。
如果事件未被处理,则过滤器将 return False
,这意味着将调用默认实现:过滤器安装在视口上,False
将使其忽略默认调用并将其转发给父级(视图本身)的 event
,并且由于自定义策略告诉发出自定义上下文菜单信号,因此您的 graphicsview_menu
函数将是实际调用:
# somewhere in the __init__
self.ui.graphicsView.viewport().installEventFilter(self)
# ...
def eventFilter(self, obj, event):
if (obj == self.ui.graphicsView.viewport() and
event.type() == event.Type.ContextMenu):
self.ui.graphicsView.contextMenuEvent(event)
return event.isAccepted()
return super().eventFilter(obj, event)
注意:上面显然假设主要class继承自QWidget(或至少QObject)。
谢谢。你的建议很有效。完全理解它有点困难,但我已经明白了。已将我的代码部分发布在 pyqt6 中,以防其他人遇到类似问题。
class ViewGraph(QDialog):
...
def __init__(self):
# Set the scene
self.scene = GraphicsScene() # QGraphicsScene class
self.ui.graphicsView.setScene(self.scene)
self.ui.graphicsView.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
self.ui.graphicsView.customContextMenuRequested.connect(self.graphicsview_menu)
self.ui.graphicsView.viewport().installEventFilter(self)
# Load items into scene
...
def eventFilter(self, obj, event):
""" This is required to forward context menu event to graphics view items """
if obj == self.ui.graphicsView.viewport() and event.type() == event.Type.ContextMenu:
self.ui.graphicsView.contextMenuEvent(event)
return event.isAccepted()
return super().eventFilter(obj, event)
def graphicsview_menu(self, position):
item = self.ui.graphicsView.itemAt(position)
if item is not None:
# Forward contextmenu event to QTextGraphicsItem, etc
self.scene.sendEvent(item)
return
# Menu for blank graphics view area
menu = QtWidgets.QMenu()
...
我在 QGraphicsView 上有一个上下文菜单。我无法激活 QTextGraphicsItem 的上下文菜单。我读到我需要向项目发送场景事件,但我找不到使 sendEvent 方法工作所需的事件。
def graphicsview_menu(self, position):
item = self.ui.graphicsView.itemAt(position)
if item is not None:
self.scene.sendEvent(item, event)
return
# Menu for blank graphics view area
menu = QtWidgets.QMenu()
...
如 contextMenuPolicy
文档所述:
The default value of this property is
Qt::DefaultContextMenu
, which means thecontextMenuEvent()
handler is called. [...] WithQt::CustomContextMenu
, the signalcustomContextMenuRequested()
is emitted.
这意味着如果您设置自定义策略,图形视图将不会调用contextMenuEvent()
,这实际上允许它最终发送一个新的图形上下文项目的菜单事件,如果它支持的话。
解决方案是在viewport(这是首先实际接收事件的地方)上安装一个事件过滤器,调用基础实现和return event.isAccepted()
的结果表明事件是否已被处理(可能显示菜单的项目)。
如果事件未被处理,则过滤器将 return False
,这意味着将调用默认实现:过滤器安装在视口上,False
将使其忽略默认调用并将其转发给父级(视图本身)的 event
,并且由于自定义策略告诉发出自定义上下文菜单信号,因此您的 graphicsview_menu
函数将是实际调用:
# somewhere in the __init__
self.ui.graphicsView.viewport().installEventFilter(self)
# ...
def eventFilter(self, obj, event):
if (obj == self.ui.graphicsView.viewport() and
event.type() == event.Type.ContextMenu):
self.ui.graphicsView.contextMenuEvent(event)
return event.isAccepted()
return super().eventFilter(obj, event)
注意:上面显然假设主要class继承自QWidget(或至少QObject)。
谢谢。你的建议很有效。完全理解它有点困难,但我已经明白了。已将我的代码部分发布在 pyqt6 中,以防其他人遇到类似问题。
class ViewGraph(QDialog):
...
def __init__(self):
# Set the scene
self.scene = GraphicsScene() # QGraphicsScene class
self.ui.graphicsView.setScene(self.scene)
self.ui.graphicsView.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
self.ui.graphicsView.customContextMenuRequested.connect(self.graphicsview_menu)
self.ui.graphicsView.viewport().installEventFilter(self)
# Load items into scene
...
def eventFilter(self, obj, event):
""" This is required to forward context menu event to graphics view items """
if obj == self.ui.graphicsView.viewport() and event.type() == event.Type.ContextMenu:
self.ui.graphicsView.contextMenuEvent(event)
return event.isAccepted()
return super().eventFilter(obj, event)
def graphicsview_menu(self, position):
item = self.ui.graphicsView.itemAt(position)
if item is not None:
# Forward contextmenu event to QTextGraphicsItem, etc
self.scene.sendEvent(item)
return
# Menu for blank graphics view area
menu = QtWidgets.QMenu()
...