Loading lots of images asynchronously
In AppWhirr we have to load a lot of icon image for store list pages. The network communication is absolutely asynchronous (even the response parsing) since we started the project but still the listing pages blocked the UI thread.
We identified the problem and it’s the icon image resource loading. We store the icon images as QPixmap as QPixmap is optimized for image drawing and we don’t have to modify these images.
Our first attempt was to load and create QPixmap in a background thread (with QRunnable and QThreadPool). It worked on Windows but didn’t boosted the performance as much as we hoped.
Then we built the Mac version and it didn’t even loaded the images. We checked the logs and we found the problem: “QPixmap: It is not safe to use pixmaps outside the GUI thread”
We searched for a solution and found that the problem is QPixmap performs some platform and painting system dependent operations. On Windows it just hangs and performed on the main-thread but on Mac it doesn’t even allow to create or change the QPixmap’s data in a background thread. Obviously none of these is ideal.
We had to find another solution and of course Qt is here to rescue. Although QPixmap cannot be created or modified in a background thread QImage can. And QPixmap can be created directly from QImage.
“QImage on the other hand is a pure platform-independent data structure optimised for direct pixel access, so it is safe to paint into a QImage. You only manipulate data managed by Qt itself - it does not use hardware acceleration and stuff. But you can’t paint into a QPixmap (or even create one) in a non-GUI thread, which is optimised for fast painting, using the underlying paint subsystem.”
(source: http://lists.trolltech.com/qt-interest/2008-11/msg00534.html )
To sum up the solution:
If you have lots of images as QByteArray resource retrieved from the server and want to present it as a QPixmap you can transform the QByteArray to QImage in a background thread (with QImage::fromData) and in the main thread you can transform the QImage to QPixmap (with QPixmap::fromImage).