Как сделать так, чтобы фигуры могли рисоваться на одном холсте?

Да у меня есть строчка self.image_foreground.fill(Qt.white) Но без неё рисование фигур "в реальном времени" не работает. Пробовал через список, но тогда не получается менять нормально цвет и толщину. Также после предварительной очистки холста не вставляется фотография. Помогите пожалуйста

import sys

from PyQt5.QtGui import QPainter, QPen, QImage
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QFileDialog
from PyQt5.QtCore import Qt, QLineF, QRectF, QPointF


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setGeometry(300, 300, 600, 600)

        mainMenu = self.menuBar()
        instmenu = mainMenu.addMenu("Инстументы")
        colormenu = mainMenu.addMenu("Цвет")
        sizemanu = mainMenu.addMenu("Толщина")
        file = mainMenu.addMenu("Файл")

        brush = QAction("Кисть", self)
        instmenu.addAction(brush)
        brush.triggered.connect(self.setBrush)

        line = QAction("Линия", self)
        instmenu.addAction(line)
        line.triggered.connect(self.setLine)

        circle = QAction("Круг", self)
        instmenu.addAction(circle)
        circle.triggered.connect(self.setCircle)

        rect = QAction("Прямоугольник", self)
        instmenu.addAction(rect)
        rect.triggered.connect(self.setRectangle)

        red = QAction("Красный", self)
        colormenu.addAction(red)
        red.triggered.connect(self.redColor)

        blue = QAction("Синий", self)
        colormenu.addAction(blue)
        blue.triggered.connect(self.blueColor)

        yellow = QAction("Желтый", self)
        colormenu.addAction(yellow)
        yellow.triggered.connect(self.yellowColor)

        black = QAction("Черный", self)
        colormenu.addAction(black)
        black.triggered.connect(self.blackColor)

        fpx = QAction("4", self)
        sizemanu.addAction(fpx)
        fpx.triggered.connect(self.four)

        epx = QAction("8", self)
        sizemanu.addAction(epx)
        epx.triggered.connect(self.eight)

        sipx = QAction("16", self)
        sizemanu.addAction(sipx)
        sipx.triggered.connect(self.sixteen)

        thpx = QAction("32", self)
        sizemanu.addAction(thpx)
        thpx.triggered.connect(self.thirtytwo)

        get = QAction('Вставить фото', self)
        file.addAction(get)
        get.triggered.connect(self.getImage)

        delete = QAction('Очистить', self)
        file.addAction(delete)
        delete.triggered.connect(self.deleteImage)

        self.image_foreground = QImage(self.size(), QImage.Format_ARGB32)
        self.image_foreground.fill(Qt.transparent)

        self.image_background = QImage(self.size(), QImage.Format_RGB32)
        self.image_background.fill(Qt.white)

        self.instrument = 'brush'

        self.brushColor = Qt.black
        self.brushSize = 8

        self.coords = QPointF()

    def getImage(self):
        filename = QFileDialog.getOpenFileName(self, "", "",
                                               "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*)")[0]
        if not filename:
            return
        self.image_background.load(filename)

    def deleteImage(self):
        self.image_foreground.fill(Qt.white)
        self.image_background.fill(Qt.white)
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(self.rect(), self.image_background, self.image_background.rect())
        painter.drawImage(self.image_foreground.rect(), self.image_foreground)


    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton and self.instrument == 'brush':
            self.coords = event.pos()
        elif event.button() == Qt.LeftButton and self.instrument == 'line':
            self.coords = event.pos()
        elif event.button() == Qt.LeftButton and self.instrument == 'circle':
            self.coords = event.pos()
        elif event.button() == Qt.LeftButton and self.instrument == 'rectangle':
            self.coords = event.pos()
        self.update()
      

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton and self.instrument == 'brush':
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawLine(self.coords, event.pos())
            self.coords = event.pos()
            self.update()
        elif event.buttons() & Qt.LeftButton and self.instrument == 'line':
            self.image_foreground.fill(Qt.white)
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawLine(self.coords, event.pos())
            self.update()
        elif event.buttons() & Qt.LeftButton and self.instrument == 'circle':
            self.image_foreground.fill(Qt.white)
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawEllipse(QRectF(self.coords, event.pos()))
            self.update()
        elif self.instrument == 'rectangle':
            self.image_foreground.fill(Qt.white)
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawRect(QRectF(self.coords, event.pos()))
            self.update()

    def mouseReleaseEvent(self, event):
        if self.instrument == 'line':
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawLine(QLineF(self.coords, event.pos()))
            self.update()
        elif self.instrument == 'circle':
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawEllipse(QRectF(self.coords, event.pos()))
            self.update()
        elif self.instrument == 'rectangle':
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawRect(QRectF(self.coords, event.pos()))
            self.update()

    def setBrush(self):
        self.instrument = 'brush'

    def setLine(self):
        self.instrument = 'line'

    def setCircle(self):
        self.instrument = 'circle'

    def setRectangle(self):
        self.instrument = 'rectangle'

    def four(self):
        self.brushSize = 4

    def eight(self):
        self.brushSize = 8

    def sixteen(self):
        self.brushSize = 16

    def thirtytwo(self):
        self.brushSize = 32

    def blackColor(self):
        self.brushColor = Qt.black

    def redColor(self):
        self.brushColor = Qt.red

    def blueColor(self):
        self.brushColor = Qt.blue

    def yellowColor(self):
        self.brushColor = Qt.yellow


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = Window()
    wnd.show()
    sys.exit(app.exec())

Ответы (1 шт):

Автор решения: gil9red

Немного поколдовал над вашим кодом и заодно поменял использование картинки заднего фона

Попробуйте:

import sys

from PyQt5.QtGui import QPainter, QPen, QImage
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QFileDialog
from PyQt5.QtCore import Qt, QLineF, QRectF, QPointF


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setGeometry(300, 300, 600, 600)

        mainMenu = self.menuBar()
        instmenu = mainMenu.addMenu("Инстументы")
        colormenu = mainMenu.addMenu("Цвет")
        sizemanu = mainMenu.addMenu("Толщина")
        file = mainMenu.addMenu("Файл")

        brush = QAction("Кисть", self)
        instmenu.addAction(brush)
        brush.triggered.connect(self.setBrush)

        line = QAction("Линия", self)
        instmenu.addAction(line)
        line.triggered.connect(self.setLine)

        circle = QAction("Круг", self)
        instmenu.addAction(circle)
        circle.triggered.connect(self.setCircle)

        rect = QAction("Прямоугольник", self)
        instmenu.addAction(rect)
        rect.triggered.connect(self.setRectangle)

        red = QAction("Красный", self)
        colormenu.addAction(red)
        red.triggered.connect(self.redColor)

        blue = QAction("Синий", self)
        colormenu.addAction(blue)
        blue.triggered.connect(self.blueColor)

        yellow = QAction("Желтый", self)
        colormenu.addAction(yellow)
        yellow.triggered.connect(self.yellowColor)

        black = QAction("Черный", self)
        colormenu.addAction(black)
        black.triggered.connect(self.blackColor)

        fpx = QAction("4", self)
        sizemanu.addAction(fpx)
        fpx.triggered.connect(self.four)

        epx = QAction("8", self)
        sizemanu.addAction(epx)
        epx.triggered.connect(self.eight)

        sipx = QAction("16", self)
        sizemanu.addAction(sipx)
        sipx.triggered.connect(self.sixteen)

        thpx = QAction("32", self)
        sizemanu.addAction(thpx)
        thpx.triggered.connect(self.thirtytwo)

        get = QAction('Вставить фото', self)
        file.addAction(get)
        get.triggered.connect(self.getImage)

        delete = QAction('Очистить', self)
        file.addAction(delete)
        delete.triggered.connect(self.deleteImage)

        self.image_foreground = QImage(self.size(), QImage.Format_ARGB32)
        self.image_foreground.fill(Qt.transparent)

        self.instrument = 'brush'

        self.brushColor = Qt.black
        self.brushSize = 8

        self.start_pos = QPointF()
        self.end_pos = QPointF()

        self.brush_points = []

    def getImage(self):
        filename = QFileDialog.getOpenFileName(
            self, "", "",
            "Images(*.png *.jpg *.jpeg);;PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*)"
        )[0]
        if not filename:
            return
        self.image_foreground.load(filename)

    def deleteImage(self):
        self.image_foreground.fill(Qt.white)
        self.update()

    def draw(self, canvas):
        painter = QPainter(canvas)
        painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))

        if self.instrument == 'brush':
            for p in self.brush_points:
                painter.drawPoint(p)

        elif self.instrument == 'line':
            painter.drawLine(self.start_pos, self.end_pos)

        elif self.instrument == 'circle':
            painter.drawEllipse(QRectF(self.start_pos, self.end_pos))

        elif self.instrument == 'rectangle':
            painter.drawRect(QRectF(self.start_pos, self.end_pos))

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(self.image_foreground.rect(), self.image_foreground)

        # Рисуем на виджете
        self.draw(self)

    def mousePressEvent(self, event):
        self.start_pos = event.pos()
        self.brush_points.clear()

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            self.end_pos = event.pos()
            self.brush_points.append(self.end_pos)

            self.update()

    def mouseReleaseEvent(self, event):
        self.end_pos = event.pos()
        self.brush_points.append(self.end_pos)

        # При отпускании кнопки мышки рисуем на картинке
        self.draw(self.image_foreground)
        self.update()

    def setBrush(self):
        self.instrument = 'brush'

    def setLine(self):
        self.instrument = 'line'

    def setCircle(self):
        self.instrument = 'circle'

    def setRectangle(self):
        self.instrument = 'rectangle'

    def four(self):
        self.brushSize = 4

    def eight(self):
        self.brushSize = 8

    def sixteen(self):
        self.brushSize = 16

    def thirtytwo(self):
        self.brushSize = 32

    def blackColor(self):
        self.brushColor = Qt.black

    def redColor(self):
        self.brushColor = Qt.red

    def blueColor(self):
        self.brushColor = Qt.blue

    def yellowColor(self):
        self.brushColor = Qt.yellow


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = Window()
    wnd.show()
    sys.exit(app.exec())

PS.

Сделал я как-то ранее простую рисовалку, возможно, она будет интересна вам: https://github.com/gil9red/fake-painter

→ Ссылка