Search code examples
pythonpyqtpyqt5pyqt4

Move the displayed PyQt5 scene


I have a QGraphicSscene in a QGraphicsView object. In my scene you can draw ROIs, so I track the mouse position all the time. Since the objects are often not very big you can zoom in on them, I would like to move the displayed scene section when the mouse is at the edge of the displayed scene. With event.scenePos() I get the position of my mouse pointer, but how can I check if I am at the edge of the scene or not?

Zooming in and out functions in my code as follows:

def zoomIn(self):
    self.view.scale(1.1, 1.1)
    # some other stuff

def zoomOut(self):
    # The initial zoom is always adapted to an image so that it is always larger or equal to the 
    # size of the GraphicsViews Object (therefore the image fills all areas). 
    if.self.currentZoom > 1: 
        self.view.scale(0.9, 0.9)
        # some other stuff

Solution

  • To determine if a point is on the edge, you have to verify that the point is inside the rectangle of the QGraphicsView viewport but outside of a smaller rectangle displaced from the previous rectangle by some pixels on all edges:

    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            scene = QtWidgets.QGraphicsScene(self)
            self.view = QtWidgets.QGraphicsView(scene)
            self.setCentralWidget(self.view)
    
            self.view.viewport().setMouseTracking(True)
            self.view.scene().installEventFilter(self)
    
        def eventFilter(self, obj, event):
            if (
                obj is self.view.scene()
                and event.type() == QtCore.QEvent.GraphicsSceneMouseMove
            ):
                vp = self.view.mapFromScene(event.scenePos())
                if self.check_if_the_point_is_on_the_edge(vp, delta=10):
                    print("on the border", event.scenePos())
            return super().eventFilter(obj, event)
    
        def check_if_the_point_is_on_the_edge(self, point, delta=1):
            rect = self.view.viewport().rect()
            internal_rect = rect.adjusted(delta, delta, -delta, -delta)
            return rect.contains(point) and not internal_rect.contains(point)
    
    
    if __name__ == "__main__":
    
        app = QtWidgets.QApplication(sys.argv)
    
        w = MainWindow()
        w.show()
        w.resize(640, 480)
    
        sys.exit(app.exec_())