Search code examples
pythonpyqtpyqt5qgraphicsviewqgraphicsscene

Bad rendering of Qrubberband in QGraphicsScene


I have a bad display for q qrubberband thought the wanted coordinates are ok :

class Viewer(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.graphicsView = QtWidgets.QGraphicsView()
        self.hbox = QtWidgets.QVBoxLayout()
        self.scene = Scene(self)
        self.splitter = QtWidgets.QSplitter()
        self.splitter.addWidget(self.graphicsView)
        self.widget.setLayout(self.hbox)
        self.setCentralWidget(self.widget)

I load a pixmap in the scene:

def open_picture(self):
        self.scene.setSceneRect(0, 0, self.pixmap.width(), self.pixmap.height())
        self.scene.addPixmap(self.pixmap)                  
        self.graphicsView.setScene(self.scene)              
        self.graphicsView.show()

and I have the scene inheritated from QGraphicsScene mostly tp handle a qrubberband on the scene

class Scene(QtWidgets.QGraphicsScene):

    def __init__(self, parent=None):
        super(Scene, self).__init__(parent)

    def mousePressEvent(self, event):
        self.originQPoint = event.scenePos()
        self.originQPoint = self.originQPoint.toPoint()
        self.currentQRubberBand = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle)

    def mouseMoveEvent(self, event):
        self.currentQRubberBand.setGeometry(QtCore.QRect(self.originQPoint, event.scenePos().toPoint()).normalized())
        self.currentQRubberBand.show()

    def mouseReleaseEvent(self, event):
        print(self.items)
        self.currentQRubberBand.hide()
        self.currentQRect = self.currentQRubberBand.geometry()
        print(self.currentQRect)

My problem is the rectangle is displaying on the screen of the my laptop but the coordinate are ok (scene coordinate) How can I draw the rubberband in the scene correctly without changing the self.currentQRect values ?enter image description here


Solution

  • According to the docs:

    QPointF QGraphicsSceneMouseEvent::scenePos() const

    Returns the mouse cursor position in scene coordinates.

    From the above we can conclude that the point we get is relative to the scene and not to the screen so it is not what we want.

    The method to use is screenPos():

    QPoint QGraphicsSceneMouseEvent::screenPos() const

    Returns the mouse cursor position in screen coordinates.

    With the above we obtain the following code:

    class Scene(QtWidgets.QGraphicsScene):
        def __init__(self, parent=None):
            super(Scene, self).__init__(parent)
    
        def mousePressEvent(self, event):
            self.originQPoint = event.screenPos()
            self.currentQRubberBand = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle)
            self.originCropPoint = event.scenePos()
    
        def mouseMoveEvent(self, event):
            self.currentQRubberBand.setGeometry(QtCore.QRect(self.originQPoint, event.screenPos()))
            self.currentQRubberBand.show()
    
        def mouseReleaseEvent(self, event):
            self.currentQRubberBand.hide()
            currentQRect = self.currentQRubberBand.geometry()
            self.currentQRect = QtCore.QRect(self.originCropPoint.toPoint(), event.scenePos().toPoint())
            print(self.currentQRect)