What is the best method/practice for emitting a signal upon entering either a QGraphicsWidget
or a QGraphicsItem
?
In my MWE I would like to trigger a call to MainWindow.update
, from Square.hoverEnterEvent
, whenever the user mouse(s) over an item in a QGraphicsScene. The trouble is that QGraphicsItem/Widget
is not really designed to emit signals. Instead these classes are setup to handle events passed down to them from QGraphicsScene
. QGraphicsScene
handles the case that the user has selected an item but does not appear to handle mouse entry events, At least there is no mechanism for entryEvent
to percolate up to the parent widget/window.
import sys
from PyQt5.QtWidgets import QWidget, QApplication, qApp, QMainWindow, QGraphicsScene, QGraphicsView, QStatusBar, QGraphicsWidget, QStyle
from PyQt5.QtCore import Qt, QSizeF
class Square(QGraphicsWidget) :
"""
doc string
"""
def __init__(self,*args, name = None, **kvps) :
super().__init__(*args, **kvps)
self.radius = 5
self.name = name
self.setAcceptHoverEvents(True)
def sizeHint(self, hint, size):
size = super().sizeHint(hint, size)
print(size)
return QSizeF(50,50)
def paint(self, painter, options, widget):
self.initStyleOption(options)
ink = options.palette.highLight() if options.state == QStyle.State_Selected else options.palette.button()
painter.setBrush(ink) # ink
painter.drawRoundedRect(self.rect(), self.radius, self.radius)
def hoverEnterEvent(self, event) :
print("Enter Event")
super().hoverEnterEvent(event)
class MainWindow(QMainWindow):
def __init__(self, *args, **kvps) :
super().__init__(*args, **kvps)
# Status bar
self.stat = QStatusBar(self)
self.setStatusBar(self.stat)
self.stat.showMessage("Started")
# Widget(s)
self.data = QGraphicsScene(self)
self.view = QGraphicsView(self.data, self)
item = self.data.addItem(Square())
self.view.ensureVisible(self.data.sceneRect())
self.setCentralWidget(self.view)
# Visibility
self.showMaximized()
def update(self, widget) :
self.stat.showMessage(str(widget.name))
if __name__ == "__main__" :
# Application
app = QApplication(sys.argv)
# Scene Tests
main = MainWindow()
main.show()
# Loop
sys.exit(app.exec_())
The docs state that QGraphicsItem
is not designed to emit signals, instead it is meant to respond to the events sent to it by QGraphicsScene
. In contrast it seems that QGraphicsWidget
is designed to do so but I'm not entirely sure where the entry point ought to be. Personally I feel QGraphicsScene
should really be emitting these signals, from what I understand of the design, but am not sure where the entry point ought to be in this case either.
Currently I see the following possible solutions, with #3 being the preferred method. I was wondering if anyone else had a better strategy :
- Create a
QGraphicsScene
subclass, let's call itScene
, to each QGraphicsItem/QGraphicsWidget and call a custom trigger/signal upon theScene
from each widget. Here I would have to subclass any item I intend on including within the scene. - Set
Mainwindow
up as the event filter for each item in the scene or upon the scene itself and callingMainWindow.update
. - Set
Mainwindow.data
to be a subclass ofQGraphicsScene
, let's call itScene
, and let it filter it's own events emitting ahoverEntry
signal.hoverEntry
is then connected toMainWindow.update
as necessary.