[PyQt] exposing QGraphicsSceneMouseEvent.setScenePos in PyQt5

Erik Hvatum ice.rikh at gmail.com
Fri Mar 13 01:30:49 GMT 2015

Hi Phil,

In sip/QtWidgets/qgraphicssceneevent.sip, the interface for
QGraphicsSceneEvent can be seen to expose a private API function
(QGraphicsSceneEvent.setWidget).  The similar private member functions for
setting the scenePos and related attributes of QGraphicsScene*Event objects
are not exposed, however.  These would be very useful for allowing
interaction with QGraphicsItems from another scene that are painted into a
QGraphicsView derivative's viewport by calling QGraphicsScene.render(..) in
the QGraphicsView derivative's drawForeground function.

For example (working example!):

 from PyQt5 import Qt
class OverlayGS(Qt.QGraphicsScene):    def __init__(self,
overlayed_scene):        super().__init__()
self.overlayed_scene = overlayed_scene
    def eventFilter(self, watched, event):        print(watched,
type(event))        if watched is self.overlayed_scene and
issubclass(type(event), (Qt.QGraphicsSceneEvent, Qt.QKeyEvent,
Qt.QFocusEvent, Qt.QTimerEvent)) or type(event) is Qt.QEvent and
event.type() is Qt.QEvent.MetaCall:#           if hasattr(event,
'screenPos') and issubclass(type(event), Qt.QGraphicsSceneEvent):#
           # Without the above, which would require exposing
QGraphicsScene*Event.setScenePos functions,            #
OverlayedGV.overlay_item receives correct mouse events only when
OverlayedGV.transform is            # identity.            return
self.event(event)        else:            return
super().eventFilter(watched, event)
class OverlayedGV(Qt.QGraphicsView):    def __init__(self, scene,
parent=None):        super().__init__(scene, parent)
self.setMouseTracking(True)        self.overlay_scene =
OverlayGS(scene)        self.overlay_item_widget = Qt.QTextEdit('hello
world\n'*4)        self.overlay_item =
    def resizeEvent(self, event):        super().resizeEvent(event)
    size = self.size()        self.overlay_scene.setSceneRect(0, 0,
size.width(), size.height())
    def drawForeground(self, p, rect):        p.save()
p.resetTransform()        try:            self.overlay_scene.render(p)
       finally:            p.restore()
if __name__ == '__main__':    import sys    app =
Qt.QApplication(sys.argv)    scene = Qt.QGraphicsScene()
big_box_item = scene.addRect(10, 10, 300, 300,
Qt.QPen(Qt.QColor(Qt.Qt.blue)), Qt.QBrush(Qt.QColor(Qt.Qt.red)))
overlayed_gv = OverlayedGV(scene)
overlayed_gv.show()    app.exec()

I think it will probably work better to make a QGraphicsView for my overlay
scene that renders to an offscreen buffer.  I can have that offscreen view
filter OverlayedGV's events before they are converted to
QGraphicsItem*Events, and I can get really clever and blit the offscreen
view's gl framebuffer into that of the OverlayedGV rather than futzing with
overlay_scene.render(..).  (Although OverlayedGV's viewport is not
necessarily a QOpenGLWidget in this example, it is in the application where
I'm doing this stuff.)

....Anyway!  Got a little off track there, but I think setScenePos,
setLastScenePos, and perhaps some other similar, supposedly private
QGraphicsEvent derivative setters would be quite convenient.  It's pretty
straightforward to modify and rebuild PyQt5 to have them, but I can't
require this of my users, and I've gone to a lot of trouble to make the
application pure Python, so including a custom sip module is also no-go.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20150312/be4f6b2e/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: t.py
Type: text/x-python
Size: 2214 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20150312/be4f6b2e/attachment-0001.py>

More information about the PyQt mailing list