'how to initiate context menu event in QGraphicsItem from QGraphicsView context menu - PyQt6
I have a context menu on the QGraphicsView. I cannot activate the context menu of a QTextGraphicsItem. I read that I need to send a scene event to the item, but I cannot find the event needed to make the sendEvent method work.
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()
...
Solution 1:[1]
As the contextMenuPolicy documentation explains:
The default value of this property is
Qt::DefaultContextMenu, which means thecontextMenuEvent()handler is called. [...] WithQt::CustomContextMenu, the signalcustomContextMenuRequested()is emitted.
This means that if you set the custom policy, the graphics view will not call contextMenuEvent(), which is what actually allows it to eventually send a new graphics context menu event to the item, if it supports it.
The solution is to install an event filter on the viewport (which is what actually receives the event in the first place), call the base implementation and return the result of the event.isAccepted(), which tells if the event was handled (an item probably showing a menu) or not.
If the event wasn't handled, then the filter will return False, which means that the default implementation would be called: the filter was installed on the viewport, False will make it ignore the default call and forward it to the event of the parent (the view itself), and since the custom policy tells to emit the custom context menu signal, your graphicsview_menu function will be actually called:
# 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)
Note: the above obviously assumes that the main class inherits from QWidget (or at least QObject).
Solution 2:[2]
Thank you. your suggestion works perfectly. Its a bit hard to understand it fully, but I am getting there. Have posted my code sections below in pyqt6 in case anyone else has similar issue.
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()
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Colin Curtain |
