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
QGraphicsScenesubclass, let's call itScene, to each QGraphicsItem/QGraphicsWidget and call a custom trigger/signal upon theScenefrom each widget. Here I would have to subclass any item I intend on including within the scene. - Set
Mainwindowup as the event filter for each item in the scene or upon the scene itself and callingMainWindow.update. - Set
Mainwindow.datato be a subclass ofQGraphicsScene, let's call itScene, and let it filter it's own events emitting ahoverEntrysignal.hoverEntryis then connected toMainWindow.updateas necessary.