Important: Please read the Qt Code of Conduct -

Manually refresh QListWidget while inserting

  • I'm currently adding a huge list of items in my QListWidget, the process takes approximately from 5 to 10 secs.

    I would like to manually refresh the new items in the widget to show the "progress", how can I efficiently do it? Apparently, calling repaint() and udpate refreshes all the items, so it takes more time as there is more items, and the widget refreshes itself when it comes back to the event loop.

    While I'm adding the items to the list, I'm using a recursive call, so I won't return to the event loop before the end.

    If possible, I would like to add an item and refresh the last item to be shown, and so on (or maybe each 5 items, for instance).

    Thank you

  • You can simply call QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);

  • @VRonin Thank you for the hint. It works almost as expected. The scrollbar shrinks but the widget stays empty. But when I focus on another app or refocus on mine, the content on the widget flashes and disappears again.

    Is it related to the speed of insertion? Is there a last thing missing?

  • Lifetime Qt Champion


    How many items are you trying to add ?

    In any case, it looks like you should rather consider QListView with a custom QAbstractListModel.

    Doing so you will be able to implement smarter algorithm to handle injection of big amount of data like batch insertion maybe a bit of thread to offload the work from the main thread etc.

    Hope it helps

  • @SGaist Thanks for the suggestion. Currently, I'm adding as much directories and files in a selected folder on the computer. So it can be from 1 to ... elements.

    Before subclassing all that, I made another class which receives the QListWidget and has a crawl method. When crawling, I tried to call: QtConcurrent::run(crawler, &Crawler::crawl), which works correctly but still freezes the GUI. Is that what you suggested?

    EDIT: BTW, I'm adding them by creating QListWidgetItems 1 by 1.

  • I was using QFuture<T>::waitForFinished() which was blocking the main thread. I now send a signal when it's finished and return peacefully to the main loop.

    I'm still unable to see the changes in the list, live. Doing a refresh (using refresh or QApplication::processEvents()) will refresh all the list, is it possible to only "commit" the last added element?

  • Lifetime Qt Champion

    Why not use a QFileSystemModel ?

  • @SGaist Because I think it would be more expensive to use this model then parse it searching for what I have to hide. So I thought, it would be faster to just recursively parse the filesystem myself and immediately sort what I need to keep or hide. Isn't it?

  • Lifetime Qt Champion

    You can add custom QSortFilterProxyModel that will remove what you don't want.

  • @SGaist Actually, "sorting" here means I have to exclude considering characteristics, like filename length. For real, is it heavier to feed the widget myself, than using the Model, View and sorter?

    If you say so, as a forgotten Qt Ambassador I can only trust a permanent Qt Champion ;)

    But I still would like to know what's the problem with my code. Anyway, I will look for the issue later

  • Lifetime Qt Champion

    It's rather the filter part that is interesting in that class for your use case.

    Not knowing your code I can't comment ;)

  • Finally... After few docs and experiences, I don't know how but I missed the fact that QWidgets are not reentrant (thanks to @kshegunov), and I also missed the fact that signals and slots are made for that.

    @SGaist So, thanks for your advices but doing real MVC made my app too complicated for what it does. In a more constructed project, I would do what you suggested. I've simplified mine:

    1. Choose your "root" directory
    2. The Crawler crawls (recursively in Qt::Concurrent) and send a signal when the QFileInfo::fileName().length() is more than x characters
    3. A slot in the MainWidget adds the item in the QListWIdget

    That's all for now (auto-rename for later), so few lines of code. Thank you for your advices.

Log in to reply