Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 4

Qt-interest Archive, February 2007
Qt 4 significantly slower than Qt 3 in showing widgets


Message 1 in thread

My team is attempting to port our software from Qt 3.3.4 to Qt 4.2.2 and all
has gone reasonably well, but now we are noticing that Qt 4 takes much
longer to switch between tabs in a QTabWidget. I have written a small
example program that demonstrates that Qt 4 takes significantly longer to
draw the selected tab than Qt 3 did. I'm sure most developers haven't
noticed this because most desktop systems are fast enough that even Qt 4
seems to change tabs instantaneously, but our target platform has a 333MHz
PowerPC processor with 128MB of memory. If you run the example program using
valgrind's cachegrind tool, it slows the execution of a desktop computer to
be similar to the speed of our target platform. You can also see the
difference in CPU time using the "time" command in Linux. My questions are:
Has anyone else noticed this kind of slowdown, and does anyone know of any
workarounds? I assume the slowness is because Qt 4 has added some features
to the painting system. We were happy with the drawing capability of Qt 3,
so if there is a way to regain the speed by disabling these features, that
would be acceptable. To this end, we tried using Qt 4's
qt_x11_set_global_double_buffer() to disable double-buffering (which is a
new feature), and that seemed to give a very minor improvement in speed, but
it made the painting process look much worse.

To head off some of the questions that people might have: We are using
Qt/X11 and can not switch to Qt/embedded because other X11 software needs to
run on the target device. We can't use a faster processor because we have to
support hardware that has already been sold. I've searched for information
about this kind of slowdown, and occasionally people will blame X11 for
being unnecessarily slow for certain operations. While this may be true, Qt
3 was apparently able to work around these problems and draw the tab
contents quickly on the same hardware and with the same version of X.

I have attached the code for the example program. It can be compiled with Qt
3 or Qt 4 and there are only a few minor preprocessor changes based on the
Qt version. The program simply creates a QTabWidget and populates it with
widgets.

Please let me know if you have any ideas or suggestions, or if you have
noticed similar behavior in other programs.
Thanks,
Tom
#include <qapplication.h>
#include <qapplication.h>
#include <qwindowsstyle.h>
#include <qtabwidget.h>
#include <qlayout.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qspinbox.h>


// Used to disable the double buffer globally. See main() to enable/disable this.
extern void qt_x11_set_global_double_buffer(bool);


/* A bunch of convenience functions for creating widgets to fill the tabs. */
void addLabel(const QString& text, QWidget* parent, QBoxLayout* layout);
void addButton(const QString& text, QWidget* parent, QBoxLayout* layout);
void addCheckBox(const QString& text, QWidget* parent, QBoxLayout* layout);
void addLineEdit(QWidget* parent, QBoxLayout* layout);
void addSpinBox(QWidget* parent, QBoxLayout* layout);
QComboBox* addComboBox(QWidget *parent, QBoxLayout *layout, 
        const QString& text1="", 
        const QString& text2="", 
        const QString& text3="", 
        const QString& text4="");
void addComboItem(QComboBox* combo, const QString& text);


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
#if QT_VERSION >= 0x040000
    // Uncomment the next line to disable Qt 4's double-buffering.
    //qt_x11_set_global_double_buffer(false);
#endif
    app.setStyle(new QWindowsStyle);
    app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));

    QTabWidget *tabs = new QTabWidget;

    QWidget *tab = 0;
    QVBoxLayout *tabLayout = 0;
    QGroupBox *group = 0;
    QVBoxLayout *groupLayout = 0;
    QHBoxLayout *rowLayout = 0;
    QComboBox *combo = 0;
    QLineEdit *lineedit = 0;

    // The first tab.
    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    group = new QGroupBox("Section 1", tab);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Combo box 1", group, rowLayout);
    addComboBox(group, rowLayout, "First choice", "Second choice", "Third choice");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Combo box 2", group, rowLayout);
    addComboBox(group, rowLayout, "Test 1", "Test 2");
    tabLayout->addWidget(group);

    group = new QGroupBox("Section 2", tab);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("More choices", group, rowLayout);
    addComboBox(group, rowLayout, "First", "Second", "Third");
    
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Type something", group, rowLayout);
    lineedit = new QLineEdit(group);
    rowLayout->addWidget(lineedit);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Choose something", group, rowLayout);
    addComboBox(group, rowLayout, "Red", "Green", "Yellow", "Blue");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Take one", group, rowLayout);
    addComboBox(group, rowLayout, "Yes", "No");
    tabLayout->addWidget(group);
    tabs->addTab(tab, "Tab 1");


    // Second tab.
    tab = new QWidget;
    rowLayout = new QHBoxLayout(tab);
    addLabel("Pick a suit", tab, rowLayout);
    addComboBox(tab, rowLayout, "Diamonds", "Hearts", "Clubs", "Spades");
    tabs->addTab(tab, "Tab 2");

    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    group = new QGroupBox("Settings", tab);
    tabLayout->addWidget(group);
    groupLayout = new QVBoxLayout(group);
    addCheckBox("Enable Something", group, groupLayout);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Type something else", group, rowLayout);
    addLineEdit(group, rowLayout);
    addButton("Default", group, rowLayout);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Make something up", group, rowLayout);
    addLineEdit(group, rowLayout);
    addButton("Default", group, rowLayout);
    group = new QGroupBox("Options", tab);
    tabLayout->addWidget(group);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addButton("Set ALL", group, rowLayout);
    addButton("Clear ALL", group, rowLayout);
    addCheckBox("Yes", group, groupLayout);
    addCheckBox("No", group, groupLayout);
    addCheckBox("Maybe", group, groupLayout);
    addCheckBox("Probably", group, groupLayout);
    addCheckBox("Almost certainly", group, groupLayout);
    addCheckBox("Unlikely", group, groupLayout);
    tabs->addTab(tab, "Tab 3");

    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("Mode", tab, rowLayout);
    addComboBox(tab, rowLayout, "Tall", "Small");
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("Pick carefully", tab, rowLayout);
    combo = new QComboBox(tab);
    rowLayout->addWidget(combo);
    addComboItem(combo, "First");
    addComboItem(combo, "Last");
    addComboItem(combo, "Middle");
    addComboItem(combo, "End");
    addComboItem(combo, "Start");
    addComboItem(combo, "Beginning");
    addComboItem(combo, "Stop");
    addComboItem(combo, "Second");
    addComboItem(combo, "Second from Last");
    addComboItem(combo, "Indecisive");
    addComboItem(combo, "Certain");
    addComboItem(combo, "Unsure");
    addComboItem(combo, "Sure");
    addComboItem(combo, "Confused");
    addComboItem(combo, "Fused");
    addComboItem(combo, "Separated");
    addComboItem(combo, "Combined");
    addComboItem(combo, "Intact");
    addComboItem(combo, "Destroyed");
    addComboItem(combo, "Undisturbed");
    addComboItem(combo, "Disturbed");
    tabs->addTab(tab, "Tab 4");

    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    group = new QGroupBox("Empty", tab);
    tabLayout->addWidget(group);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("March", group, rowLayout);
    addComboBox(group, rowLayout, "One by one", "Two by two", "Three by three", "Hoorah");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("April", group, rowLayout);
    addComboBox(group, rowLayout, "First", "Fifteenth", "Showers");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Direction", group, rowLayout);
    addComboBox(group, rowLayout, "Up", "Down");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Type", group, rowLayout);
    addComboBox(group, rowLayout, "Great", "Grand");
    tabs->addTab(tab, "Tab 5");

    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    group = new QGroupBox("Almost finished", tab);
    tabLayout->addWidget(group);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Specification", group, rowLayout);
    addComboBox(group, rowLayout, "A", "B", "C");
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Pick two", group, rowLayout);
    addComboBox(group, rowLayout, "One");
    group = new QGroupBox("Not quite finished", tab);
    tabLayout->addWidget(group);
    groupLayout = new QVBoxLayout(group);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Type anything", group, rowLayout);
    addLineEdit(group, rowLayout);
    rowLayout = new QHBoxLayout;
    groupLayout->addLayout(rowLayout);
    addLabel("Finish", group, rowLayout);
    addComboBox(group, rowLayout, "No", "Yes");
    tabs->addTab(tab, "Tab 6");

    tab = new QWidget;
    tabLayout = new QVBoxLayout(tab);
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("No?", tab, rowLayout);
    addComboBox(tab, rowLayout, "Yes", "No", "Maybe");
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("Duration", tab, rowLayout);
    addSpinBox(tab, rowLayout);
    addSpinBox(tab, rowLayout);
    addSpinBox(tab, rowLayout);
    addSpinBox(tab, rowLayout);
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("Date", tab, rowLayout);
    addButton("Today", tab, rowLayout);
    addSpinBox(tab, rowLayout);
    rowLayout = new QHBoxLayout;
    tabLayout->addLayout(rowLayout);
    addLabel("Time", tab, rowLayout);
    addButton("Now", tab, rowLayout);
    addSpinBox(tab, rowLayout);
    tabs->addTab(tab, "Tab 7");


    tabs->resize(800, 550);
    tabs->show();

    return app.exec();
}


void addComboItem(QComboBox* combo, const QString& text)
{
#if QT_VERSION >= 0x040000
    combo->addItem(text);
#else
    combo->insertItem(text);
#endif
}

void addLabel(const QString& text, QWidget *parent, QBoxLayout *layout)
{
    QLabel *label = new QLabel(text, parent);
    layout->addWidget(label);
}

void addButton(const QString& text, QWidget *parent, QBoxLayout *layout)
{
    QPushButton *button = new QPushButton(text, parent);
    layout->addWidget(button);
}

void addCheckBox(const QString& text, QWidget *parent, QBoxLayout *layout)
{
    QCheckBox *checkbox = new QCheckBox(text, parent);
    layout->addWidget(checkbox);
}

void addSpinBox(QWidget *parent, QBoxLayout *layout)
{
    QSpinBox *spinbox = new QSpinBox(parent);
    layout->addWidget(spinbox);
}

void addLineEdit(QWidget *parent, QBoxLayout *layout)
{
    QLineEdit *lineedit = new QLineEdit(parent);
    layout->addWidget(lineedit);
}

QComboBox* addComboBox(QWidget *parent, QBoxLayout *layout, const QString& text1, const QString& text2, const QString& text3, const QString& text4)
{
    QComboBox *combo = new QComboBox(parent);
    if (!text1.isEmpty())
        addComboItem(combo, text1);
    if (!text2.isEmpty())
        addComboItem(combo, text2);
    if (!text3.isEmpty())
        addComboItem(combo, text3);
    if (!text4.isEmpty())
        addComboItem(combo, text4);
    layout->addWidget(combo);
    return combo;
}