PDA

View Full Version : Adding QStackedWidget to QScrollArea



sattu
31st July 2014, 10:14
Hi Everyone,

I have 2 QWidget classes in my Project by name Widget and TestWidget. In my Widget Class I have the following objects declared-

widget.h


TestWidget* objTest;
QScrollArea scrollArea;
QStackedWidget stackedWd;


and in widget.cpp


objTest = new TestWidget;

scrollArea.setParent(this);
scrollArea.setGeometry(20,20,360,100);

scrollArea.setHorizontalScrollBarPolicy(Qt::Scroll BarAlwaysOff);
scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBa rAsNeeded);
scrollArea.setWidget(&stackedWd);
//scrollArea.setWidget(objTest);

stackedWd.addWidget(objTest);
stackedWd.setCurrentWidget(objTest);
objTest->raise();
objTest->activateWindow();


But unfortunately nothing is visible in the QScrollArea. On the contrary if I exclude QStackedWidget then TestWidget appears fine in the ScrollArea along with the scroll, following is the code for it-

widget.cpp


objTest = new TestWidget;

scrollArea.setParent(this);
scrollArea.setGeometry(20,20,360,100);

scrollArea.setHorizontalScrollBarPolicy(Qt::Scroll BarAlwaysOff);
scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBa rAsNeeded);
scrollArea.setWidget(objTest);


I am just not able to understand why the same thing doesn't happen when I use a QStackedWidget as an intermediate. It would be great if someone would guide me regarding this.

For more info TestWidget is a simple QWidget class with just a QLabel in it. The size of TestWidget is 320x240.

wysota
31st July 2014, 11:16
You are not using layouts, as far as I can tell, which may indicate that the stacked widget size is 0. Keeping widget objects as members of another widget class is also not the best idea, you should keep pointers instead and allocate objects in constructor of the parent widget.

sattu
31st July 2014, 11:37
You are not using layouts, as far as I can tell, which may indicate that the stacked widget size is 0.
Where should I put the Layout? I mean I should add the ScrollArea to the GridLayout or the StackedWidget to the GridLayout?

Keeping widget objects as members of another widget class is also not the best idea, you should keep pointers instead and allocate objects in constructor of the parent widget.
I have taken a pointer only naa? And the particular code is inside the constructor of Widget class, to put the full code-


Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
objTest = new TestWidget;

scrollArea.setParent(this);
scrollArea.setGeometry(20,20,360,100);

scrollArea.setHorizontalScrollBarPolicy(Qt::Scroll BarAlwaysOff);
scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBa rAsNeeded);
scrollArea.setWidget(&stackedWd);
//scrollArea.setWidget(objTest);

stackedWd.addWidget(objTest);
stackedWd.setCurrentWidget(objTest);
objTest->raise();
objTest->activateWindow();
}

By the way, why is it a bad idea?

wysota
31st July 2014, 11:52
Where should I put the Layout? I mean I should add the ScrollArea to the GridLayout or the StackedWidget to the GridLayout?
I don't see any GridLayout here. You should apply a layout to your "Widget" instance instead of using setGeometry, etc.


Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
QVBoxLayout *l = new QVBoxLayout(this); // <-- create layout for the widget
scrollArea = new QScrollArea(this);
l->addWidget(scrollArea); // <-- put scroll area into the layout
stackedWd = new QStackedWidget(scrollArea);
scrollArea->setWidget(stackedWd);
scrollArea->setWidgetResizable(true); // <-- allow the scroll area to manage its client widget size
}


I have taken a pointer only naa?
Naa :)


And the particular code is inside the constructor of Widget class, to put the full code-

scrollArea.setParent(this);
The dot indicates this is not a pointer.


By the way, why is it a bad idea?
Because parents free their child widgets when they are themselves deleted and compiler will try to delete the same object when its scope ends resulting in a possible double-free error.

sattu
31st July 2014, 12:11
I don't see any GridLayout here. You should apply a layout to your "Widget" instance instead of using setGeometry, etc.
Thanks a lot, first step achieved :). Now the TestWidget is visible in the ScrollArea. But the scroll doesn't appear, do I have to enable any other option along with Resizable factor?



Naa :)
I thought you were speaking of TestWidget class. :D

wysota
31st July 2014, 12:37
If you make the client widget resizable then it will be resized to the scroll area ;) If you want scroll bars to appear, you have to enforce a size on the client widget so that it doesn't fit the scroll area and scroll bars will appear. So basically the client widget has to tell that it cannot be smaller than X but it can be larger than that. If X is lower than the scroll area size then scroll area will enlarge the client to its own size. If X is larger than the scroll area, then scroll bars will appear.

sattu
31st July 2014, 13:27
If you make the client widget resizable then it will be resized to the scroll area ;) If you want scroll bars to appear, you have to enforce a size on the client widget so that it doesn't fit the scroll area and scroll bars will appear. So basically the client widget has to tell that it cannot be smaller than X but it can be larger than that. If X is lower than the scroll area size then scroll area will enlarge the client to its own size. If X is larger than the scroll area, then scroll bars will appear.
Thanks a lot wysota. It took me some time to understand the Minimum Size concept and what should be it's idle value. I am setting the minimum size of the StackedWidget as follows-


stackedWd->setMinimumSize(objTest->width(),objTest->height());

I hope I understood it correct.

wysota
31st July 2014, 13:45
stackedWd->setMinimumSize(objTest->width(),objTest->height());

Well... This does not basically make much sense. You should have a layout there as well and the layout should be responsible for managing the size. Your first step should really be to start using layouts everywhere instead of manual setGeometry calls.

sattu
31st July 2014, 15:14
Well... This does not basically make much sense. You should have a layout there as well and the layout should be responsible for managing the size. Your first step should really be to start using layouts everywhere instead of manual setGeometry calls.
Okies, I am going to explore that next. Just for the sake of trying I used a GridLayout in my TestWidget class, as a result of which I am able to get the scrollBar without having to manually call the Geometry functions, as mentioned by you.
But then the spacing between the Child Widgets (of the GridLayout) change when I run the program compared to how it appears in the .ui file (I used drag and drop for a quick trial). So I will get back once I have read the documentation and gone through some Layout examples. :)