nzz coding
nzz coding

Reputation: 47

QPainter delete previously drawn shapes

I am trying to code a simple image editor like paint.

I implemented drawing lines rectangles and ellipses.

what i want is to see an animation (a foreshadowing ?) of how the rectangle will look like, just like in paint when you draw a shape you can see what it actually looks like without really drawing on the canvas.

here is a shortened version of the code

class Canvas(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()
        self.initLogic()

    def initUI(self):
        self.image = QImage(self.size(), QImage.Format_RGB32)
        self.image.fill(Qt.white)

    def initLogic(self):
        self.brushSize = 1
        self.brushStyle = Qt.SolidLine
        self.brushColor = QColor(0, 0, 0)
        self.shapeMode = None

        self.drawing = False
        self.mousePointer = None

    def mousePressEvent(self, event):
        self.drawing = True
        self.mousePointer = event.pos()

    def mouseMoveEvent(self, event):
        #if no pen mode set draw lines from event to event
        if self.drawing:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor,
                                self.brushSize,
                                self.brushStyle))
            
            shape = None #i try later to assign the method Qpainter.draw<someShape> to this variable
            #             hoping it works like in tkinter.
            if self.shapeMode == None:#free shape
                painter.drawLine(self.mousePointer, event.pos())
                self.mousePointer = event.pos()

            else:
                #previous x and previous y
                ox, oy = self.mousePointer.x(), self.mousePointer.y()
                #current x and current y
                dx, dy = event.pos().x(), event.pos().y()
                width, height = dx - ox, dy - oy
                #self.shapeMode is a string corresponding to a QPainter method
                #we get the corresponding method using getattr builtin function
                drawMethod = getattr(painter, self.shapeMode)# = painter.someFunc this works fine
                shape = drawMethod(ox, oy, width, height) #assigning the method call to a variable

            self.update()
            if shape != None:
                painter.eraseRect(shape)

        """
        if self.drawing and self.shapeMode == None:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor,
                                self.brushSize,
                                self.brushStyle))
            painter.drawLine(self.mousePointer, event.pos())
            self.mousePointer = event.pos()
            self.update()"""
        #otherwise if pen mode set draw shape at event then delete until release


    def mouseReleaseEvent(self, event):
        if self.shapeMode != None:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor,
                                self.brushSize,
                                self.brushStyle))

            #previous x and previous y
            ox, oy = self.mousePointer.x(), self.mousePointer.y()
            #current x and current y
            dx, dy = event.pos().x(), event.pos().y()
            width, height = dx - ox, dy - oy
            #self.shapeMode is a string corresponding to a QPainter methid
            #we get the corresponding method using getattr builtin function
            drawMethod = getattr(painter, self.shapeMode)# = painter.someFunc
            shape = drawMethod(ox, oy, width, height)
            self.update()

        self.mousePointer = event.pos()
        self.drawing = False
        #TODO end registering the action

    def paintEvent(self, event):
        widgetPainter = QPainter(self)
        widgetPainter.drawImage(self.rect(), self.image, self.rect())

the canvas keeps drawing rectangles as long as i hold the mouse, what i want is the rectangle to resize and only definitively be drawn after mouse release.

Upvotes: 1

Views: 1757

Answers (1)

alec
alec

Reputation: 6112

You can achieve this by taking advantage of which paint device to pass to QPainter. During mouseMoveEvent keep a reference to the points and sizes calculated so in paintEvent you can draw onto the main widget. This way anything painted will only last until the next update. Then in mouseReleaseEvent you can paint on the QImage to permanently draw the rectangle.

class Canvas(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()
        self.initLogic()

    def initUI(self):
        self.image = QImage(self.size(), QImage.Format_RGB32)
        self.image.fill(Qt.white)

    def initLogic(self):
        self.brushSize = 1
        self.brushStyle = Qt.SolidLine
        self.brushColor = QColor(0, 0, 0)
        self.shapeMode = 'drawRect'
        self.temp_rect = QRect()

        self.drawing = False
        self.mousePointer = None

    def mousePressEvent(self, event):
        self.drawing = True
        self.mousePointer = event.pos()

    def mouseMoveEvent(self, event):
        #if no pen mode set draw lines from event to event
        if self.drawing:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor,
                                self.brushSize,
                                self.brushStyle))

            if self.shapeMode == None:#free shape
                painter.drawLine(self.mousePointer, event.pos())
                self.mousePointer = event.pos()

            else:
                #previous x and previous y
                ox, oy = self.mousePointer.x(), self.mousePointer.y()
                #current x and current y
                dx, dy = event.pos().x(), event.pos().y()
                width, height = dx - ox, dy - oy

                self.temp_rect = QRect(ox, oy, width, height)

            self.update()
            
    def mouseReleaseEvent(self, event):
        if self.shapeMode != None:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor,
                                self.brushSize,
                                self.brushStyle))

            #self.shapeMode is a string corresponding to a QPainter methid
            #we get the corresponding method using getattr builtin function
            drawMethod = getattr(painter, self.shapeMode)# = painter.someFunc
            drawMethod(self.temp_rect)
            self.update()

        self.mousePointer = event.pos()
        self.drawing = False
        #TODO end registering the action

    def paintEvent(self, event):
        widgetPainter = QPainter(self)
        widgetPainter.drawImage(self.rect(), self.image, self.rect())
        if self.drawing:
            drawMethod = getattr(widgetPainter, self.shapeMode)
            drawMethod(self.temp_rect)

Outcome:

enter image description here

Upvotes: 1

Related Questions