[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):#
event.setScenePos(event.widget().mapFromGlobal(event.screenPos()))
# 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 =
self.overlay_scene.addWidget(self.overlay_item_widget)
self.overlay_item.show()
self.overlay_scene.changed.connect(self.scene().invalidate)
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()
scene.setBackgroundBrush(Qt.QBrush(Qt.QColor(Qt.Qt.black)))
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)
scene.installEventFilter(overlayed_gv.overlay_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.
Thanks,
Erik
-------------- 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