PDA

View Full Version : QScrollArea With Custom Widgets



VireX
20th April 2007, 07:34
Ok let's say you have a program like structured like this:

CObject Objects in the table, like 25
CTable Table for QScrollArea
main where you display QScrollArea

In CTable you do this (assume all objects declared):



CTable::CTable(QWidget *parent) : QWidget(parent) {
iObjects = 25;
QGridLayout *lay = new QGridLayout;
setLayout(lay);
for(int i = 0; i < iObjects; i++){
buttons << new QPushButtons(QString("%1").arg(i));
}
}
void CTable::resizeEvent(QResizeEvent *evt){
// ASSUME XPOS AND YPOS ARE CORRECTLY DECLARED
for(int i = 0; i < iObjects; i++){
buttons[i]->move(xpos*150+10, ypos*101+10);
}
}


And in main


QScrollArea* qs = new QScrollArea;
qs->setWidget(ctable);



Code has been shortened for clarity!!!

The idea here is, I am building 25 custom widgets (I used buttons here for simplicity, with a QList), and they have to automatically resize and list themselves (the dimensions are 150 by 100), like as if you would see a test with problems in them. It will go like this:

1 2 3 4 5
6 7 8 9 10
11 12.....

Problem is when I compile this code, it will not show the objects, it will show them all in one spot (so all 25 are in same spot so you only see ONE).

Need help please.

aamer4yu
20th April 2007, 07:38
Where are u adding the buttons to the grid layout ??

VireX
20th April 2007, 08:30
I'm not... but I am declaring the pushbuttons as parent "this".
but I have tried addWidget on each, but didn't get me very far.

jpn
20th April 2007, 08:39
I'd suggest reading about Layout Classes (http://doc.trolltech.com/4.2/layout.html). ;)

marcel
20th April 2007, 09:07
Are you creating the buttons directly in the scroll area?
If so, it's not OK. You must create another widget that you will set as the scroll area contents with QScrollArea::setWidget and then create your buttons with this widget as parent. Also, the grid layout must be set for this widget.

Regards

jpn
20th April 2007, 09:20
You must create another widget that you will set as the scroll area contents with QScrollArea::setWidget and then create your buttons with this widget as parent.
He is doing so:


QScrollArea* qs = new QScrollArea;
qs->setWidget(ctable);




Also, the grid layout must be set for this widget.

He is doing that too:


QGridLayout *lay = new QGridLayout;
setLayout(lay);


It's just the actual usage of the layout that's missing. :)

VireX
20th April 2007, 09:26
I would suggest... you're right.

But see, when I do this:
lay->addWidget(cobject[i]);

and then compile...
All I see is one widget (I believe the others are underneath it).

move I guess doesn't work with QGridLayout, but I tried removing QGridLayout, and it seems thats not the problem. So I'm wondering... is move a useless function that only works when it feels like it?

jpn
20th April 2007, 09:39
Use QGridLayout::addWidget() which takes a row and column number. Oh, and you can forget about resizing and moving by hand when a layout is in use. :)

wysota
20th April 2007, 09:47
Shouldn't the layout be applied on the viewport and not directly on the scroll area?

jpn
20th April 2007, 09:50
Shouldn't the layout be applied on the viewport and not directly on the scroll area?
But then it wouldn't make any sense to use a scroll area? His layout is applied on the widget inside the scroll area as I see is correct.

wysota
20th April 2007, 11:24
Oh, right. I didn't notice that.

VireX
20th April 2007, 18:18
See it's not working. Inside my main loop, I tried addWidget(cobjects[i], i, i); just to see if i can get more than one, but nooooo, still one damn widget in one damn top left corner.

Also, lemme list something, the QScrollArea is there for a reason. Because there will always be vertical scroll, since there may be a high number of objects. Let's say the person maximizes the program the program will go from:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24

to

1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24

Understand??
So in other words, I dont even know if I should use grid layout, because I need the positions of the objects to change according to the size of the widget. And I don't see no "ChangeItemPos()"... And eliminating the gridlayout does the same thing, even with no gridlayout move doesnt' work... WHY?

wysota
20th April 2007, 18:21
Could you prepare a small compilable example and attach it here?

VireX
20th April 2007, 18:25
ok hold on... but btw, i updated my last post. Ima have to do it after lunch.

wysota
20th April 2007, 18:35
You should use the flow layout (or whatever it's called) instead of grid layout. It's bundled with Qt as one of its examples.

VireX
20th April 2007, 19:05
I tried using a flowlayout,
with Cobjects, it doesn't work, still same problem.
With QPushButtons, it lists them like so:
1 2 3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 21 23 24

But, I don't want to scroll horizontally, so flowlayout is useless to me, because it doesn't adjust itself to fit the size of the QScrollArea and window. There should never be a need to use horizontal scroll, it should automatically reorder itself to fit vertical scroll only.

wysota
20th April 2007, 19:42
What is a CObject? Obviously you can only put QObjects into layouts. And the flow layout does work for you - it layouts widgets, it doesn't control size of the parent widget - you have to control that yourself. Did you make the widget of the viewport resizable? Maybe it'll adjust itself to the scrollarea then.

VireX
20th April 2007, 20:07
CObject inherits QObject. CObject has like 2 buttons.
I don't understand what you mean but I'm about to upload the test rar i prepared for you to better understand.

I can't believe VBulletin doesn't accept rar, who doesn't use rar... :S.

Also an interesting find:
I tried this:
flow->addWidget(new QPushButton("bla"));

and it crashes

but when I do
flow->addWidget(new CObject(this));

it works fine. Meaning QPushButtons don't work with flowlayouts... odd. Hmm I noticed that it works only if i resize the widget, i guess some sort of size causes flowlayouts to crash.

But mainly the bigger problem is, when you have QPushButtons it seems to have the illusion that its working except ResizeEvent doesn't work AT ALL. However, why the hell does my widget only become 1 widget, why can't i ever see more than one? Why doesn't the 24 widgets I make become visible?

wysota
20th April 2007, 21:55
I guess the thing attached is what you wanted.

VireX
21st April 2007, 00:06
Yes that's exactly what I wanted... now i'm gonna try it with my object class.

Nope, it's not working with FlowLayout,.. My class that inherits QWidget, with parent wgt.

So basically, flowlayout only works with QPushButtons, and other widgets, not with widgets with multiple buttons and QLabels.

wysota
21st April 2007, 00:19
Works quite fine for me.

VireX
21st April 2007, 07:37
Take a look, whenever I create this class, I changed your class in a very SIMPLE fashion. Logically thinking this should work fine, just a bunch of widgets just as you did, but how does your code magically work but these widgets magically not work?

See attachment ... thx we're getting close.

wysota
21st April 2007, 13:14
The reason is simple and I can tell you just by looking at your code - you didn't use layouts and you didn't reimplement sizeHint(). At least one of the two has to be used for layouts to work. Otherwise QWidget::sizeHint() will be used and I'm sure it doesn't return a reasonable size for your widget.

VireX
22nd April 2007, 03:19
Wrong, thats not the problem because I put some gridlayouts and did some sizeHint reimplementing, and nothing... can you please try and compile mine the way you believe works?

marcel
22nd April 2007, 03:34
Looking at your code, I see one big problem:

Complex widget does not have a layout to handle it's size, that is why you don't see anything ( at least I don't ). So after creating the widgets inside it, you should use setFixedSize( cumulatedSize ), where cumulatedSize is the total size of the widgets inside Complex ( I used 100, 100 and it worked, but probably the size is smaller ).

Also, to see any of the widgets whatsoever, create the widgets in complex with "this" as parent... Not having a layout makes them not having any parent, therefore no one to forward them paint events( actually this is more important than the 1st problem )

I hope you agree.

regards

marcel
22nd April 2007, 03:39
I did the following modification ( at the end of the Complex constructor )



#include <QtGui>
#include "flowlayout.h"
#include <QResizeEvent>

class Complex : public QWidget {
public:
QPushButton *Host;
QPushButton *Info;
QLabel *qlGameNum;
QLabel *qlGameTitle;
QLabel *qlPlayerNum;
QLabel *qlIcons;
Complex(int i, QWidget *parent=0): QWidget(parent){
/*QHBoxLayout *l = new QHBoxLayout(this);
l->addWidget(new QPushButton(QString("Button %1").arg(i)));
QComboBox *cb = new QComboBox;
cb->addItems(QStringList() << QString::number(i));
cb->setMinimumWidth(50);
l->addWidget(cb);*/
Host = new QPushButton( this ) ;
Host->setObjectName(QString::fromUtf8("Host"));
Host->setGeometry(QRect(20, 50, 61, 41));
Info = new QPushButton( this );
Info->setObjectName(QString::fromUtf8("Info"));
Info->setGeometry(QRect(80, 60, 31, 21));
qlGameNum = new QLabel( this );
qlGameNum->setObjectName(QString::fromUtf8("qlGameNum"));
qlGameNum->setGeometry(QRect(10, 0, 46, 14));
qlGameTitle = new QLabel(this);
qlGameTitle->setObjectName(QString::fromUtf8("qlGameTitle"));
qlGameTitle->setGeometry(QRect(10, 20, 61, 16));
qlPlayerNum = new QLabel(this);
qlPlayerNum->setObjectName(QString::fromUtf8("qlPlayerNum"));
qlPlayerNum->setGeometry(QRect(130, 0, 21, 16));
qlIcons = new QLabel(this);
qlIcons->setObjectName(QString::fromUtf8("qlIcons"));
qlIcons->setGeometry(QRect(65, 0, 61, 20));
Host->setText(QApplication::translate("Form", "Host", 0, QApplication::UnicodeUTF8));
Info->setText(QApplication::translate("Form", "Info", 0, QApplication::UnicodeUTF8));
qlGameNum->setText(QApplication::translate("Form", "Game 1", 0, QApplication::UnicodeUTF8));
qlGameTitle->setText(QApplication::translate("Form", "Game Title", 0, QApplication::UnicodeUTF8));
qlPlayerNum->setText(QApplication::translate("Form", "0/8", 0, QApplication::UnicodeUTF8));
setFixedSize( 200, 100 );
}
};

class Widget : public QWidget {
public:
Widget(QWidget *parent = 0) : QWidget(parent){}
bool eventFilter(QObject *o, QEvent *e){
if(e->type()!=QEvent::Resize) return false;
QResizeEvent *ev = (QResizeEvent*)e;
int w = ev->size().width()-20; // cheating here
setFixedSize(w, layout()->heightForWidth(w));
return false;
}
};

int main(int argc, char **argv){
QApplication app(argc, argv);
QScrollArea area;
QWidget *wgt = new Widget;
FlowLayout *l = new FlowLayout(wgt);
for(int i=0;i<20;i++)
l->addWidget(new Complex(i+1, wgt));
wgt->setMinimumSize( wgt->sizeHint() );
area.setWidget(wgt);
area.installEventFilter(wgt);
area.show();
return app.exec();
}


I also attached a screenshot of what I obtained.

Regards

marcel
22nd April 2007, 03:43
My suggestion:
Use a layout in Complex too, because it is not recommended to place widgets manually within a parent widget. After all, that is what layouts are for.

Placing widgets manually is tedious, and as the number of widgets increases the code gets hard to maintain and to read and also this leads to a lot of useless coordinate computations. You should let a layout do this for you.

Regards

wysota
22nd April 2007, 09:58
Wrong, thats not the problem because I put some gridlayouts and did some sizeHint reimplementing, and nothing... can you please try and compile mine the way you believe works?

I don't know what "some" is, but I'm sure the problem is with the size hint. What marcel said just proves that.

marcel
22nd April 2007, 10:03
I don't know what "some" is, but I'm sure the problem is with the size hint. What marcel said just proves that.


Yes, with the sizeHint exactly...
There is no one to compute the size hint for the Complex widget... It should be set manually.

Or Virex should use layouts...

Regards

wysota
22nd April 2007, 10:06
Yes, with the sizeHint exactly...
There is no one to compute the size hint for the Complex widget... It should be set manually.

Or Virex should use layouts...


This is exactly what I said two posts ago :)

VireX
22nd April 2007, 17:48
THanks, adding setLayout (forgot I didn't declare the gridlayout as parent so i didn't setLAyout) and setFixedSize did the trick.