Why should I destroy a QPainter after use? Can I keep it?
-
I have a PyQt app that draws a lot of simple square rectangles on a QImage. The "draw a few squares" function gets called a whole lot of times and sometimes hundreds of times a second. (I'm emulating a primitive black and white screen for a retro-computer.)
I have followed the advice in the QPainter page, which says,
Construct and customize (e.g. set the pen or the brush) the painter. Then draw. Remember to destroy the QPainter object after drawing.
So my "draw a few squares" function creates a QPainter as a local variable, calls its fillRect() a few times, then exits (destroying the QPainter).
Is this necessary? My QImage is not changing. Would it be valid to create a single QPainter at the same time I create the QImage on which it paints, and use it multiple times?
-
@dcortesi QPainters are temporary objects. There are a few reasons for this, the ones I remember are:
- Only 1 painter can be attached to a device at a time. So if you left your QPainter active anything else that calls
begin()
would fail, critically. - Constructing the painter on a device calls
begin()
for you. And deconstructing it will automatically callend()
. So It is really intended to be a one use fire and forget type of object.
I'm sure if you dug into the Qt code you would find numerous other reasons for the "make sure you deconstruct this" message in the docs. I don't know more off the top of my head. My guess is it all has to do with my reason #1.
- Only 1 painter can be attached to a device at a time. So if you left your QPainter active anything else that calls
-
Thanks for the info. I only do two things with the QImage.
- Paint rectangles on it with
my_painter.fillRect( x, y, w, h, color )
- Copy it into a bitmap with
QBitmap:fromImage( my_image )
The bitmap is then displayed by applying it to a QLabel with
setPixmap()
.Those two steps are done over and over and over: paint some rectangles, then copy the updated image as a bitmap and apply it to the label. Repeat.
So the question would be, does QBitmap::fromImage() call this
begin()
method? If not, the QPainter would have the image for itself. - Paint rectangles on it with
-
I will answer my own question: for the particular use I described, it works to keep a QPainter around and re-use it with the identical QImage. There was no conflict between calling QBitmap::fromImage() and having an active QPainter on the source QImage.
There are times in my app where I replace the QImage, for example on a reSizeEvent I have to make a bigger or smaller one, and then I need to discard the QPainter also, and make a new one.
Also my code that uses the QPainter can be called from different QThreads, and it is essential to only use a QPainter from the same thread that created it. Using it -- or destroying it -- from a different QThread than created it, causes a crash. But when I sorted that out, it works to retain the QPainter.
-
Also my code that uses the QPainter can be called from different QThreads, and it is essential to only use a QPainter from the same thread that created it. Using it -- or destroying it -- from a different QThread than created it, causes a crash. But when I sorted that out, it works to retain the QPainter.
@dcortesi This is normal for any QWidget. If you access it in a thread that it doesn't belong to it will crash.
As for the other part it's definitely not meant to be used that way but if it's working you can use it for now. Expect weird crashes in the future if things change under the surface in Qt though. I would err on the side of caution and not save/reuse that QPainter. :)