Lazy Loading File Icons to QTableWidget?
-
wrote on 14 May 2018, 13:23 last edited by ScottLupton
I'm displaying the contents of a directory in a
QTableWidget
along with the file icons. I've found that it can take a long time to load the icons, particularly with icons that are embedded in executable files. To make the application more responsive I changed it to show the directory contents immediately and then tried to load the icons gradually from a worker thread. However, I'm not sure how to implement the icon loading in the worker thread.I tried creating an
IconLoader
class to load the icons from aQFileIconProvider
in a worker thread:struct IconRequest { QFileInfo fileInfo; int row; QIcon icon; }; class IconLoader : public QObject { Q_OBJECT private: QFileIconProvider m_IconProvider; signals: void IconReady(IconRequest* request); private slots: void LoadIconReq(IconRequest* request); { request->icon = m_IconProvider.icon(request->fileInfo); emit IconReady(request); } };
I created connections for requesting and receiving icons and moved the
IconLoader
to aQThread
:m_IconLoader = new IconLoader; m_IconLoader->moveToThread(&m_IconLoaderThread); connect(this, SIGNAL(RequestingIcon(IconRequest*)), m_IconLoader, SLOT(LoadIconReq(IconRequest*))); connect(m_IconLoader, SIGNAL(IconReady(IconRequest*)), this, SLOT(SetIcon(IconRequest*))); connect(&m_IconLoaderThread, SIGNAL(finished()), m_IconLoader, SLOT(deleteLater())); m_IconLoaderThread.start();
After the
IconReady()
signal is emitted by the worker thread theSetIcon()
slot is called in the main thread (m_dirListing
is a pointer to aQTableWidget
):void FileList::SetIcon(IconRequest* request) { m_dirListing->item(request->row, 0)->setIcon(request->icon); delete request; }
Unfortunately, the directory contents still do not display until all the icons have loaded. Investigating the problem it appears that
QFileIconProvider::icon()
is actually a very fast operation that returns immediately. The time consuming operation seems to beQTableWidgetItem::setIcon()
which appears to be where the icon is actually loaded. AsQTableWidgetItem::setIcon()
is called from the main thread the program still becomes unresponsive when loading directories.Since the above approach doesn't work I'm unsure how to get lazy loading of icons to work.
QTableWidgetItem::setIcon()
couldn't be called from the worker thread sinceQTableWidgetItem
is reenterant and not thread-safe.How can I load the icon in the worker thread so it can be quickly set in the main thread?
-
Use an own model and set the data there. QTableWidget is just a convenience class which was designed for simple stuff (just like QTreeWidget).
-
wrote on 14 May 2018, 17:26 last edited by
That probably would have been best, but at this point it would require a lot of changes.
The application is complete and generally works well, but I later found that opening directories containing a lot of executables with embedded icons could be very slow. I was hoping to find a way of addressing that without making major changes.
1/3