3
votes

my application (Qt 4.6) requires me to display certain messages in a list which always scrolls down upon adding a new line (so the most recent line is always visible).

As I am having performance issues in the whole process which includes displaying these one-line messages, I've run some tests and found the QListWidget I am using for this to be the main issue.

I've created a simple test project with a default list widget "listWidget" and a push button "pushButton" which adds 1000 items in a loop on click. Those two widgets are added in a layout on the main window. Here's the .cpp code (.h is default + the slot definition)

#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);    
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_released()
{
    for( int iLine = 0; iLine < 1000; iLine++ )
    {
        ui->listWidget->addItem(
            QString( "%1: This is a dummy text" )
            .arg( QString::number( iLine ).rightJustified( 4, '0' ) )
            );
        ui->listWidget->scrollToBottom();
        QApplication::processEvents();
    }
}

Without the scrollToBottom() the performance is alright, but if I add scrollToBottom, it also requires me to add processEvents() for a repaint, and things start getting really slow. When you resize the height of the window (and implicitly the list widget), you can literally watch the update speed changing.

I've tried playing around with performance flags like adding the following lines to the constructor:

ui->listWidget->setLayoutMode( QListWidget::Batched );
ui->listWidget->setBatchSize( 10 );

This speeds it up alot, but scrollToBottom() does no longer work.

Does anyone have an idea how to improve the speed? Feel free to suggest completely different approaches as long as they're using Qt.

[Edit] Taking a look at the performance of e.g. the Details list in the Install Dialogue of Qt Creator or programs like wireshark which don't have problems displaying a couple of lines per second, I know autoscrolling lists which update at a high speed are possible in general. The main question is: Is this possible with Qt?

2

2 Answers

8
votes

The view tries to calculate the individual size of each new item. Since you probably don't need that, you can disable it and gain some speed with:

ui->listWidget->setUniformItemSizes(true);

And you don't really need either to "update the widget whenever a line is added", even if that was possible, because you won't see any difference above a certain update rate.
So, you can use a timer (QTime or QElapsedTimer) to limit the rate at which you actually scroll and force a repaint:

void MainWindow::on_pushButton_released()
{
    static QTime rateTimer;
    rateTimer.start();

    for( int iLine = 0; iLine < 50000; iLine++ )
    {
        ui->listWidget->addItem(
              QString( "%1: This is a dummy text" )
              .arg( QString::number( iLine ).rightJustified( 5, '0' ) )
              );

        // Limit at 60 updates/s
        if(rateTimer.elapsed() > 1000/60) {
            ui->listWidget->scrollToBottom();
            QApplication::processEvents();
            rateTimer.restart();
        }
    }
    // For the items added after the last processEvents()
    ui->listWidget->scrollToBottom();
}

But for very large lists, you might have to write your own model derived from QAbstractListModel, because QListWidget insertion speed seems to decrease rapidly with the number of item already in the list.

2
votes

I am not sure if this will solve your problem or not but it may offer a different approach.

QWidget has updatesEnabled property that allows your control whether widget receives paint events or not.

Try disabling this properyt then populate your list and then re-enable it to paint your widget back.

I hope this helps.