Important: Please read the Qt Code of Conduct -

Optimizations / Substituions for QListWidget?

  • Is there any way to optimize the setting of a ListWidgetItem's widget in a QListWidget?, currently when i have a list of ~ 200 items, setting the item's widgets causes my app to freeze whilst it is doing that for ~ 15 seconds, The only thing the widget that im setting it to contains is three QLabels, one for a text field, and one for an image, and one for a color block. Even when i dont initialize the widget's ui, and simply set it to an empty widget it still takes a high amount of time.

    I don't believe i can thread it as it involves UI elements, so i'm not sure if im doing something wrong, or if QListWidget isnt the data view i should be using in this situation?

    I didn't post any code because its litteraly just making a new QListWidgetItem, adding it to the list, then setting its widget to a custom widget with a UI, in a loop for a search result, which can range from 3-500 results

  • Lifetime Qt Champion

    You must be doing something wrong - adding 200 items will not take 15s. Please show us your code.

  • Moderators

    @SolaVitae said in Optimizations / Substituions for QListWidget?:

    Labels, one for a text field, and one for an image

    please show us, how you create the custom ListWidgetItems.

    If you for example create a new QImage /QPixmap for each of your 200 entries, that can take a really long time to do, depending on how you do it.

  • They are created like so:

    while ( {
    		QString iconUrl = q.value(5).toString();
    		QString fileName;
    		ItemSearchItem *isi = new ItemSearchItem();
    		QListWidgetItem *lwi = new QListWidgetItem();
    		lwi->setSizeHint(QSize(210, 30));
    		fileName = ac()->dataPath + "\\cache\\icons\\" + q.value(1).toString() + ".png";
    		if (!fileExists(fileName)) {
    			//downloadList.insert(iconUrl, isi->uid);
    		resultList->setItemWidget(lwi, isi);
    		uidIndex.insert(q.value(1).toString(), isi);

    Q is a QSqlQuery, the constructor/definition for ItemSearchItem is:

    class ItemSearchItem : public QWidget {
    	explicit ItemSearchItem(QWidget *parent = 0);
    	Ui::ItemSearchItem *ui;
    	QString itemName;
    	QString iconPath;
    	QLabel *itemIconLabel;
    	QLabel *itemNameLabel;
    	QString link;
    	QString uid;
    ItemSearchItem::ItemSearchItem(QWidget *parent) :
    	itemNameLabel = findChild<QLabel*>("itemName");
    	itemIconLabel = findChild<QLabel*>("itemIcon");

    the Constructor typically has a UI setup line in it, but i removed it for testing, and commenting out the setItemWidget line results in it finishing in less than 1 second

  • Moderators

    @SolaVitae said in Optimizations / Substituions for QListWidget?:

    the Constructor typically has a UI setup line in it, but i removed it for testing, and commenting out the setItemWidget line results in it finishing in less than 1 second

    Yeah I believe that to be the issue.

    You create a new QImage/QPixmap in your UI-file each time you call new. That will take time, parsing the file in your ressources, consturcting an Qimage then displaying it.

    Much cheaper should be if you modify your constructor, so that it expects an QImage, Than you create the Qimage before your Query and simply pass it as a copy, much cheaper than new construction.

    Should increase the speed significantly.

  • @J.Hilk
    I thought that might have some effect on it, but even when I remove every line from the constructor, and remove all references to the ui, even removing the include for it, and it still takes abnormal amounts of time, Even when i circumvent the entire ItemSearchItem, and just try to set it to a regular empty QWidget it still takes awhile.

    But, after just adding empty widgets to items after, to test the speed comparison of adding custom widgets, versus adding empty stock QWidgets, i noticed it took about twice as long, which lead me to my solution. I don't know why exactly, but adding a list item, then setting its widget in a loop seems to take an increasing amount of time based on how many items you've added, after each item it would take more and more time to set the widget of the next item. So from that i just made two loops instead of one, one to add all the items, and then one after to set all the item widgets, and now it takes less than 1 second to complete both operations.

  • setItemWidget should come with a huge warning about it being the wrong solution in 90% of the cases.

    What you need is a QStyledItemDelegate.
    use QListWidgetItem::setData to store your text, image and color in 3 different roles (Qt::EditRole, Qt::DecorationRole and Qt::UserRole appear to be the most natural choices)

    then subclass QStyledItemDelegate and reimplement paint (you can find Qt's implementation here to use as a starting point)

    finally just call QListWidget::setItemDelegate to assign the delegate to the view

Log in to reply