Search code examples
performanceqtresizerowqtablewidget

QTableWidget resizeRowsToContents very SLOW


I've a QTableWidget that contains over 200.000 rows and 8 columns. The columns has a fixed size. The rows has a variable size. Adding the items to the table is fast (few seconds).

Then the call of resizeRowsToContents() takes almost 60/120 seconds! I see that this call is single thread! (Only one core works). Can I force MultiThreading ? How Can I speedup the row resizing ?

Thank you, Salvo


Solution

  • One thing you might try is to update the QTableWidget row-by-row using QTableWidget::resizeRowToContents(Note: Row rather than Rows) with the updates being interleaved with other events in the queue. Overall the process would still take the same amount of time but your GUI would remain responsive during the process.

    Firstly, take advantage of the fact that a QTimer with a zero timeout will emit its timeout signal whenever the event queue becomes empty. So code such as...

    QTimer::singleShot(0, &my_callback);
    

    will effectively wait until the event queue is empty and then invoke my_callback. If my_callback calls the same line of code then you have a function that automatically invokes itself during the next idle period.

    Now write the function...

    void resize_row (QTableWidget *view, int row, int count = 1)
    {
    
        /*
         * Resize rows `row' -> `row + count - 1'
         */
        for (int todo = count; row < view->rowCount() && todo--; ++row) {
            view->resizeRowToContents(row);
        }
    
        /*
         * If there are still rows remaining then reschedule.
         */
        if (row < view->rowCount()) {
            QTimer::singleShot(0, [=](){ resize_row(view, row, count); });
        }
    }
    

    This will invoke view->resizeRowToContents(...) on all rows in the range [row, row + count). If the row index is still less that the row count it will schedule itself for the next idle period with updated parameters.

    Now, replace...

    table_widget->resizeRowsToContents();
    

    with...

    QTimer::singleShot(0, [table_widget, row = 0](){ resize_row(table_widget, row, 10); });
    

    Seems to work fine in the basic tests I've done.