Search code examples
pyqt5qrect

Problem in drawing Rectangle with mouse event in QGraphicScene


I have a class for draw rectangle and it works but when dragging rect and start_point(QPoint) is bigger than end_point, current rect won't show.

this clip show what is my problem! enter image description here and the code:

class RectangleScene(QGraphicsScene):
    def __init__(self, *args, **kwargs):
        super(RectangleScene, self).__init__(*args, **kwargs)
        self.graphics_line = None
        self.start_point = QtCore.QPointF()
        self.end_point = QtCore.QPointF()

    def clean_scene(self):
        for index, item in enumerate(self.items()[:-1]):
            if index > 1:


    def mousePressEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.clean_scene()
            self.start_point = event.scenePos()
            self.end_point = self.start_point
            self.graphics_line = QtWidgets.QGraphicsRectItem(QtCore.QRectF(self.start_point, self.end_point))
            self.addItem(self.graphics_line)
            self.update_path()

        elif QtCore.Qt.RightButton and self.graphics_line:
            self.contextMenuEvent(event)
            super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.end_point = event.scenePos()
            self.update_path()
            super(RectangleScene, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.end_point = event.scenePos()
            self.update_path()
            super(RectangleScene, self).mouseReleaseEvent(event)

    def update_path(self):
        if not self.start_point.isNull() and not self.end_point.isNull():
            self.graphics_line.setRect(QtCore.QRectF(self.start_point, self.end_point))
            self.graphics_line.setPen(QPen(
                QColor(242, 219, 7),
                3,
                QtCore.Qt.SolidLine,
                QtCore.Qt.FlatCap,
                QtCore.Qt.RoundJoin,
            ))

but when right click for context menu invisible rect showed.


Solution

  • You need to normalize your QRectF:

    class RectangleScene(QGraphicsScene):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.graphics_line = None
            self.start_point = QPointF()
            self.end_point = QPointF()
    
        def clean_scene(self):
            for index, item in enumerate(self.items()[:-1]):
                self.removeItem(item)
    
        def mousePressEvent(self, event):
            if event.buttons() & Qt.LeftButton:
                self.clean_scene()
                self.start_point = event.scenePos()
                self.end_point = self.start_point
                self.graphics_line = QGraphicsRectItem(
                    QRectF(self.start_point, self.end_point).normalized()  # here
                )
                self.addItem(self.graphics_line)
                self.update_path()
            elif Qt.RightButton and self.graphics_line:
                self.contextMenuEvent(event)
                super().mousePressEvent(event)
    
        def mouseMoveEvent(self, event):
            if event.buttons() & Qt.LeftButton:
                self.end_point = event.scenePos()
                self.update_path()
            super().mouseMoveEvent(event)
    
        def mouseReleaseEvent(self, event):
            if event.buttons() & Qt.LeftButton:
                self.end_point = event.scenePos()
                self.update_path()
            super().mouseReleaseEvent(event)
    
        def update_path(self):
            if not self.start_point.isNull() and not self.end_point.isNull():
                self.graphics_line.setRect(
                    QRectF(self.start_point, self.end_point).normalized()  # here
                )
                self.graphics_line.setPen(QPen(
                    QColor(242, 219, 7), 3, Qt.SolidLine,
                    Qt.FlatCap, Qt.RoundJoin,))