Important: Please read the Qt Code of Conduct -

Compute-intensive paintEvent

  • I need some advice. My QWidget::paintEvent() method can result in some fairly expensive computation if the paint region is large. This results in a laggy unresponsive application when this happens. Here are the solutions (as I see them):

    1. Create a worker thread that does the update in the background--- sync the worker thread with the gui thread somehow (maybe a queue of paint regions in the worker thread.)

    2. Figure out a way to process events from within paintEvent so the application is more responsive while the computation is taking place. But when I call qApp->processEvents() from within paintEvent(), it crashes.

    3. Similar to (2), display a wait cursor (if I could figure out how to process events from within paintEvent).

    Any advice/ideas?


  • I suggest looking into decoupling the paint event from the computation. This can be done by rendering into a QImage from a worker thread when the data model updates, ideally tiled, so that the algorithm can make use of multiple CPUs. In the paintEvent, simply clip the pre-rendered QImage into the paint region.

    A further improvement would be to render into a OpenGL texture (from the workers), that saves the extra conversion from QImage during painting.

  • Agreed: a threaded solution is almost certainly what you want here. As miroslav suggests, you can even get sophisticated and support multiple threads, but I'd say start out with the simple case of just doing the rendering in a single thread and get that working before playing around with tiling, etc.

  • Thanks guys--- I've been playing with the worker thread, and I'm learning some things:

    1. You can't paint outside of paintEvent() -- my first assumption was that you could, but it makes sense why you can't (something to do with backingstore?) This leaves me with the problem of how to synchronize my worker thread with the gui thread--- my worker thread can render to an object (QImage) but how to get that image painted from within paintEvent?. The only thing that comes to mind is to signal the gui thread to issue a repaint() and then use the pre-rendered object from within paintEvent to paint with. So there will need to be some logic in paintEvent to distinguish between a paintEvent() initiated from repaint() and a paintEvent() initiated from a gui event.

    2. I'm getting 2 calls to paintEvent for each time I scroll or resize the window. The event->rect() are the same for both calls. Is there a recommended way to deal with this given that my painting is expensive? I guess I could look at the rects and discard the 2nd one if it's the same.

    Am I barking up the right tree(s)?

    thanks much!

  • There is an example for drawing using threads, from the top of my head it is some fractal drawing thing. That might give you some clues on how to implement it.

    I would not just disregard paint events. That might result in artefacts on screen. Once you have offloaded the expensive part to another thread, you won't need to anyway.

  • [quote author="Andre" date="1325074863"]There is an example for drawing using threads, from the top of my head it is some fractal drawing thing. That might give you some clues on how to implement it.[/quote]

    It's in examples/threads/mandelbrot and creates a Mandelbrot set.

Log in to reply