如何从 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()
    ...