PDA

View Full Version : Performance in hiding/showing widgets



Paalrammer
5th February 2007, 11:49
Hi, I'm new to QT programming and I'm stuck with an annoying issue.
I am working on an application that needs to display about 250 widgetsin a ScrollArea. I have a button that collapses most of these widgets (using hide()). Pushing the button again will show() the widgets again.
Re-showing the widgets after they have been hidden is however quite slow (too slow in my opinion). This slowness is bad, but what is worse is that when I show() the widgets again, you can see the widgets get added an resized.

I have run my app on an old notebook and I get the exact same behaviour.
I have tried using setUpdatesEnabled, but that didn't make it any better.
I thought that maybe the ScrollArea is slowing it down. Or the QVBoxLayout. But none of this was true.
I'm under the impression that when I start the app, it actually draws faster than when I do a show() after a hide().

I'm using QT 4.2.2 Open source version on Windows XP. I'm compiling with Visual C++ 2005 Studio Express.
I'm including source code that isolates the problem. It is not the complete app of course, but it shows what is going wrong. I'm creating 50 buttons that are hidden when you push the "Push Me" button. Maybe on another system you'd need to use 250 buttons to see clearly what is happending.

Thanks for any help,

p

PS. Actually I don't really want to use 250 widgets, but I don't have a choice as the QTreeWidget does not allow me to have a QTreeWidgetItem span multiple columns (something the Java version appears to allow?).


The header file scroll.h:


#ifndef SCROLL_H_
#define SCROLL_H_

#include <QtGui>

class MyFrame: public QScrollArea
{
Q_OBJECT
public:
MyFrame(QWidget* parent=0);
public slots:
void change(bool dummy);
private:
enum {number=50};
QPushButton* pbs[number];
QFrame *frame;
QFrame *labelframe;
QVBoxLayout *lay;
QVBoxLayout *labellay;
bool seeMe;
};

#endif


The main code "scroll.cpp":


#include <QtGui>
#include "scroll.h"

MyFrame::MyFrame(QWidget* parent): QScrollArea(parent), seeMe(1)
{
setWidgetResizable(true);

frame=new QFrame;
frame->setFrameShape(QFrame::Box);

QPushButton *push=new QPushButton(tr("Push me"));
connect(push, SIGNAL(clicked(bool)), this, SLOT(change(bool)));
labelframe=new QFrame;

lay=new QVBoxLayout;
lay->addWidget(push);
lay->addWidget(labelframe);
lay->addStretch(1);
frame->setLayout(lay);

labellay=new QVBoxLayout;
for (int i=0; i<number; i++) {
pbs[i]=new QPushButton(tr("Button %1").arg(i));
labellay->addWidget(pbs[i]);
}
labellay->addStretch(1);
labelframe->setLayout(labellay);

setWidget(frame);
}

void MyFrame::change(bool dummy)
{
seeMe=!seeMe;
// labelframe->setUpdatesEnabled(false); // doesn't help much
labelframe->setVisible(seeMe);
// labelframe->setUpdatesEnabled(true);
}

int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyFrame mf;
mf.show();
return app.exec();
}

sarode
5th February 2007, 12:20
Hi..

I am using Qt 4.1.0 on Linux and its working fine ...
i tested your code here. But i didnot find anything what you are talking about

Cheers

Paalrammer
6th February 2007, 13:07
Thanks sarode,

At least this confirms that my code isn't complete rubbish.
Is there anybody out there who could compile the code on his/her setup. I'd be interested in knowing if the buttons get redrawn fast on QT 4.1 or 4.2 on Windows. Is is probably better to set number to 250 to get a better idea of what is the problem. Basically it draws the buttons in two (or more phases), first some lines with text, next the complete button.
Heck, even a web app would be much faster than what I'm seeing now in this native app. If I can't resolve this problem I think I will have to check out wxWidgets again, which is sad as I was just starting to like QT.

regards,
p

wysota
6th February 2007, 13:12
Maybe you should just change the design? Hiding and showing several hundred widgets is not a best idea regardless of what it is doing. setUpdatesEnabled() won't change anything as eventually the scroll area will have to update itself. Maybe you could use a tree view instead of standalone widgets?

Paalrammer
6th February 2007, 15:13
Wysota,

Thanks for the reply. Let me explain what I'm trying to create. It is basically a list of titles which can be collapsed or expanded, just like in a tree. All these title contain some attributes with their value. It should look something like this:


(-) SOMEWHAT LONG TITLE
attribute1 La lalal
attribute2 Chah chah cha
attribute3 tralalala
(+) EVEN A MUCH LONGER TITLE
(+) SOME MORE TITLE
(-) AGAIN A TITLE THAT COULD BECOME QUITE LONG
attribute1 Some value
attribute2 Flop Flop
attribute8 Chop Chop
attribute12 More nonsense
attribute12 Gibberish
.
.
.
(+) ALMOST LAST TITLE
(+) THE LAST TITLE

So I'd have about 20 of these titles that could be collapsed. Sounds like the perfect job for a tree view, I thought. I tried that, but as I the TreeItems cannot span columns (I think), I got the following result (my titles get cut off):


(-) SOMEWHAT LON...
attribute1 La lalal
attribute2 Chah chah cha
attribute3 tralalala
(+) EVEN A MUCH ...
(+) SOME MORE TITLE
(-) AGAIN A TITL...
attribute1 Some value
attribute2 Flop Flop
attribute8 Chop Chop
attribute12 More nonsense
attribute12 Gibberish
.
.
.
(+) ALMOST LAST ...
(+) THE LAST TITLE


So I implemented the titles myself as a inherited QLabel and added a TableView for each title to represent the attributes. Everything works very fast: scrolling, editing, resizing the mainwindow, ... I added a button that collapses all titles at the same time (using hide). This worked really fast as well. Next I added a button to expand all collapsed titles in one go. This was sloooow. The time between button push and final result was long, but what was worse: you can see the table widgets being drawn and expanded. This takes about 3 to 4 seconds on my machine.
I have also tried implementing the attributes with a Tree and with just QLabels and QLineInput, but it didn't help much when I restored the hidden widgets with show().

So, maybe you can tell me if there is a better way to implement what I'm trying to do? I have looked at all the available widgets and Tabs/Stacked/Tool boxes are really cool, but they take away the overview the user needs to have of all the attributes.
So, the only thing I can think of right now is reimplementing the painting routine of the QTree in order to have my titles take up the full width of the tree, instead of just the first column. Would that be feasible or just a mad newbie idea?
Apparently Jambi (QT in Java) already has this functionality in QTreeWidgetItem, although I don't really understand the description completely:


public final void setSpanning(boolean span)

Sets the first section to span all columns if expand is true, otherwise all item sections are shown.


Maybe this is something we can expext on a next version of QT for C++?

Help!

p

wysota
6th February 2007, 16:04
I'll start answering in the reverse order :)

Yes, you can expect that to work in upcoming Qt releases. It's possible that it works with recent snapshots already.

Even if it doesn't I'm sure you can get a simmilar behaviour either by reimplementing the delegate (if the view doesn't fill the background of its items before calling the delegate) or by reimplementing the view (if the view destroys the background of its items).
In the former case you just need to change the rectangle used to paint the display role of the first column and do nothing for the second column. If latter is the case, you need to stop the view from painting the first column of the top level items and modify the rectangle before calling the delegate. I guess that's more or less what setSpanning does anyway.

And if that doesn't fit your needs (or is impossible to achieve) maybe you can simply have a single column in the view and separate the attribute names from values using a custom delegate?

Paalrammer
6th February 2007, 17:02
Aha, thanks. I think I know what to do now. Time to dig deeper into QT I guess.
Maybe I should have asked how to override the QTreeView behaviour in the first place :-)

p

wysota
6th February 2007, 17:40
Time to dig deeper into QT I guess.
QT = QuickTime(R) by Apple
Qt = Quasar toolkit (or other legendary explanation of "Q toolkit" name) by Trolltech.


Maybe I should have asked how to override the QTreeView behaviour in the first place :-)
Maybe you should have :)

Paalrammer
13th February 2007, 14:53
Just a quick note to tell the people about my next steps/

Apparently VMWare is free nowadays, so I installed Linux and did some speed tests. Although the screen driver is very slow, the app with 250 buttons acts very fast under Linux. However when I try my complete program the widget drawing is even slower than on Windows. So as Wysota told me, it is not a good idea to draw too many widgets.

I have tried extending the behaviour of the QTreeView class by having items span more than one column, but failed miserably. Though I had a lot of fun trying. And some nice effects.

So, in the end I thought it would be better to check if the snapshots for Qt 4.3 had the desired "span" featured and they did. Compilation under Linux was easy, Windows with Visual C++ was a bit annoying, but I now have the desired behaviour out of the box. Yeah. Thanks for all the help.

VireX
14th February 2007, 06:20
QT = QuickTime(R) by Apple
Qt = Quasar toolkit (or other legendary explanation of "Q toolkit" name) by Trolltech.


Maybe you should have :)

who the hell uses quicktime except when viewing some idiots website?

jpn
14th February 2007, 06:52
who the hell uses quicktime except when viewing some idiots website?
The point was that people tend to mix them up. This forum focuses on Qt, not on QT. Which are two different things..

VireX
14th February 2007, 18:41
obviously, why would we discuss QT in here?

wysota
14th February 2007, 18:57
obviously, why would we discuss QT in here?

We wouldn't, but many people write "QT" when referring to "Qt", so sometimes we tend to point out that difference.