Search code examples
multithreadingqtqpixmap

Need performance improvement advice on Qt Painting


To make it simple, my application has two scroll bars. when any scroll bar changes, the QPainter re-paints images.

code pieces:

  // connect valueChanged to update
  connect(this->horizontalScrollBar(),
      SIGNAL(valueChanged(int)),
      this,
      SLOT(UpdateVisibleArea()));

  connect(this->verticalScrollBar(),
      SIGNAL(valueChanged(int)),
      this,
      SLOT(UpdateVisibleArea()));

in UpdateVisibleArea(), the QWidget.update() method is called. and the QWidget.paintEvent() method is implemented like the following:

QPixmap q_pixmap;
if (!ImageCache::GetPixmap(cache_key, &q_pixmap)) {
    // there're up to thousands of images, we can not pre-load them all into the cache.
    // the following statement may take 80~250ms.
    loadImage(cache_key, &q_pixmap);    
    ImageCache::PutPixmap(cache_key, q_pixmap);
}

QPainter q_painter;
q_painter.drawPixmap(...);  // usually it takes less than 20ms.

The problem:

when I drag scroll bars quickly, it feels pretty laggy.

My thoughts:

  1. The images should be loaded in background thread. but the problem is, the qpainter instance is waiting on the UI thread. it can not proceed when the image is not ready.
  2. Is there any way to prevent repainting happening so fast when scroll bar changes quickly?

My question:

Can you please give me some clue on how to optimize it?


Solution

  • How can I optimize the complex drawing for many objects in scrolled content?

    That can be done with "offscreen rendering" when we populate the graphics buffer before it is actually drawn on the screen. In case of scrolling we can either prepopulate the whole scroll content as one big rectangular area or we can use large enough rectangular "window" so that we scroll easier. Should we use smaller scroll window buffer and not the whole scroll rectangle for the offscreen rendering depends on the size of the scrolled content.

    Using OpenGL and framebuffer can improve this technique even further. That can be done either with QOpenGLWidget or using QML QQuickPaintedItem (that implies entire UI is QML, though). The second example is not elaborated for the offscreen buffer technique, though, but just shows the use of framebuffer in QML. That same technique from the first example can be applied there with a bit of change.