Flicker-Free Custom Painting in Qt 3
I wrote a small Qt 3 widget that draws a graph, and it flickered whenever another window crossed it. The first version painted the background and graph directly onto the widget. The user could occasionally see the exciting interval between those operations.
The obvious cure is to draw a complete frame off-screen and copy it in one operation.
void Graph::paintEvent(QPaintEvent *event)
{
QPixmap frame(size());
frame.fill(colorGroup().base());
QPainter p(&frame);
drawGrid(&p);
drawValues(&p);
p.end();
bitBlt(this, event->rect().topLeft(), &frame, event->rect());
}
The pixmap receives the background and every graph element before the screen changes, so the widget never displays a half-painted frame. For a frequently updated widget, I keep a cached pixmap and rebuild it only when the size, palette, or data changes.
Calling update() schedules a paint event and allows Qt to combine several dirty regions. Calling repaint() paints immediately. I use update() unless the application genuinely requires synchronous drawing; repeated immediate paints are an efficient way to make smooth animation less smooth.
Another option is the WNoAutoErase widget flag, which prevents Qt from erasing the background before paintEvent(). It can remove one source of flicker, but then the paint code must cover every exposed pixel. Missing one produces attractive garbage from whichever window was there before.
Double buffering costs memory proportional to the widget area, and redrawing an elaborate pixmap for every tiny exposure wastes time. Respect the event’s rectangle and cache expensive static parts.
The result is not clever: compose, then copy. That is precisely why I like it. Rendering bugs are much easier to diagnose when the screen sees only finished frames.