Warm tip: This article is reproduced from stackoverflow.com, please click
pyqt5 python

How to use QtPainter after starting the UI and later when a button is pressed?

发布于 2020-03-27 10:19:26

I'm writing a simulation GUI, in which QtPainter is draws a Pixmap instantly when the windows is opening. I use different buttons, that are supposed to result in painting on top of the pixmap (lines and other geometric forms)

I've tried writing functions that take the QtPainter object as an argument and use button.clicked.connect() to call the functions but the drawings never appear on screen. As I am new to PyQt I am not sure with how it works, but I guess I can only paint by calling the paintEvent() function, but if I write all geometric forms in paintEvent(), how do I make sure they only appear when the button is pressed?

Questioner
frfritz
Viewed
22
Heike 2019-07-04 02:15

To draw directly onto a widget you can override it's paintEvent. The thing to remember when doing so is that paintEvent fires every time the Widget deems it necessary to redraw itself e.g. when it has been resized or moved. This means that when implementing your own version of paintEvent you need to draw all the shapes you want drawn on your widget. Note that paintEvent is rarely called directly. If you want the widget to redraw itself, you should call update() which will schedule a paintEvent for you.

Here is a simple example where arbitrary rectangles are added to a canvas when clicking on a button. The rectangles are stored in an array in the Canvas object. In Canvas.paintEvent, we create an instance of QPainter and use this object to draw all the rectangles in the array.

from PyQt5 import QtWidgets, QtGui, QtCore
from random import randrange

class Canvas(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.rectangles = []

    def add_rectangle(self, rect, color):
        self.rectangles.append((rect, color))
        self.update()

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        brush = QtGui.QBrush(QtCore.Qt.white)
        painter.setBrush(brush)
        painter.drawRect(event.rect())

        pen = QtGui.QPen()
        pen.setWidth(3)
        for rect, color in self.rectangles:
            pen.setColor(color)
            painter.setPen(pen)
            brush.setColor(color)
            painter.setBrush(brush)
            painter.drawRect(rect)

class MyWindow(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.canvas = Canvas(self)
        self.button = QtWidgets.QPushButton('Add rectangle')
        self.button.clicked.connect(self.add_rectangle)

        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.addWidget(self.canvas)
        self.layout.addWidget(self.button)
        self.resize(500,500)

    def add_rectangle(self):
        w = self.canvas.width()
        h = self.canvas.height()
        x0, y0 = randrange(w), randrange(h)
        x1, y1 = randrange(w), randrange(h)

        shape = QtCore.QRect(min(x0,x1), min(y0,y1), abs(x0-x1), abs(y0-y1))
        color = QtGui.QColor.fromRgb(*(randrange(256) for i in range(3)), 180)
        self.canvas.add_rectangle(shape, color)


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    window = MyWindow()
    window.show()
    app.exec()