PDA

View Full Version : How to change QMainWindow size at runtime?



myfifth
6th January 2011, 09:22
Since there was no chance to determine the size of main window at very beginning, I have to change it later, at runtime.

Basically my main window contained a toolbar, menu bar, as well as status bar. Then
when the first child widget (will be central widget of main window) was created, it's best chance for me to adjust the size.

The code liked below,


// first set child widget geometry
setGeometry(rect);

// adjust main window accordingly
mainWnd->setCentralWidget(this);
mainWnd->adjustSize();

// I also tried below
// mainWnd->updateGeometry();

Besides, I've overridden sizeHint() of main window to return a QSize(0, 0), since it said if sizeHint() returned an invalid value, adjustSize() would set the size to the children rectangle that covers all child widgets.

However, the resulting size of main window was totally too small than I expected.
I'm really confused how Qt size policy was working.

Could anyone help me?
Thx.

high_flyer
6th January 2011, 09:42
I am not sure I understand what it is you want to achieve, and more so why.
Have you tried resize()?

Also, if your main window needs to have a certain specific size, then you can have sizeHint() return it, in addition, if your main window should not change size you should set the sitzePolicy() to fixed.
But fixed sized main window (or windows that need to have more specific size than using the min and max size limits) shows more that you probably don't need a main window, and probably more a dialog.

Maybe if you explain more what it is and why you are trying to do, we might help you get on the right track.

myfifth
6th January 2011, 11:09
Basically, I'd like to build an app with main window by following steps,

1. build main window (size was not determined yet at this moment). now, main window only contained toolbar, menu, status bar, without a central widget
2. then dynamically create the first widget (QFrame-derived), it would be central widget of main window and it would expand main window size according to its size
3. continue to dynamically create some widgets and add them to central widget.

Briefly, main window size depends on central widget size.

Since main window size = all bars size + central widget size,
so resize() didn't work for my case, it actually resized entire geometry area which contains those bars, but I've no idea about what those bars size are.

Hopefully I'm clear for you.
Thanks.

wysota
6th January 2011, 11:26
First make sure your central widget is using layouts properly. Then put it into the main window (if you really need a main window) and set the main window layout's size constraint (not size policy of any of the widgets) to QLayout::SetFixedSize (or SetMinimumSize).

myfifth
7th January 2011, 06:28
I built a simple demo to show what problem I've got,



QMyMainWindow::QMyMainWindow(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

QFrame* frame = new QFrame(this);
setCentralWidget(frame);

frame->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

QRect rect(0, 0, 240, 320);
frame->setFrameShape(QFrame::Box);
frame->setLineWidth(3);
frame->setFrameShadow(QFrame::Plain);
frame->setGeometry(rect);

adjustSize();
}


I didn't specify main window size at first and it would be totally expanded by central widget.
I also tried other SizePolicy values, but the resulting size of main window was not (240, 320) as expected at all.

How could I do?
Thx

Lykurg
7th January 2011, 07:58
You have to resize() your mainwindow, not the frame inside it. And calling adjustSize() destroy all other setting you made before.

myfifth
7th January 2011, 09:22
I've found the root cause



QSize QWidgetPrivate::adjustedSize() const
{
Q_Q(const QWidget);

QSize s = q->sizeHint();

if (q->isWindow()) {
Qt::Orientations exp;
if (layout) {
if (layout->hasHeightForWidth())
s.setHeight(layout->totalHeightForWidth(s.width()));
exp = layout->expandingDirections();
} else
{
if (q->sizePolicy().hasHeightForWidth())
s.setHeight(q->heightForWidth(s.width()));
exp = q->sizePolicy().expandingDirections();
}
if (exp & Qt::Horizontal)
s.setWidth(qMax(s.width(), 200));
if (exp & Qt::Vertical)
s.setHeight(qMax(s.height(), 100));
#if defined(Q_WS_X11)
QRect screen = QApplication::desktop()->screenGeometry(q->x11Info().screen());
#else // all others
QRect screen = QApplication::desktop()->screenGeometry(q->pos());
#endif
#if defined (Q_WS_WINCE) || defined (Q_OS_SYMBIAN)
s.setWidth(qMin(s.width(), screen.width()));
s.setHeight(qMin(s.height(), screen.height()));
#else
s.setWidth(qMin(s.width(), screen.width()*2/3));
s.setHeight(qMin(s.height(), screen.height()*2/3));
#endif
if (QTLWExtra *extra = maybeTopData())
extra->sizeAdjusted = true;
}

if (!s.isValid()) {
QRect r = q->childrenRect(); // get children rectangle
if (r.isNull())
return s;
s = r.size() + QSize(2 * r.x(), 2 * r.y());
}

return s;
}


The root was that window has a default size policy, so adjustSize() never ran into using childrenRect to expand size. How could I avoid to it?

Added after 4 minutes:


You have to resize() your mainwindow, not the frame inside it. And calling adjustSize() destroy all other setting you made before.

but I can't get the total size of frame plus other bars (toolbar, menubar, etc).

wysota
7th January 2011, 10:55
size policy is only relevant for widgets inside layouts. Your main window is not inside a layout. Furthermore your frame doesn't have a layout attached so it's sizeHint is practically 0. Hence the size of your mainwindow content is also 0. Why do you keep going the wrong way despite being told a couple of times how you should approach your problem? childrenRect() will likely use sizeHint() of your child widgets and since sizeHint of the frame is 0, you will get a useless output for the whole calculation. And even if not then your frame is controlled by a layout so using setGeometry() on it has no effect at all.

myfifth
7th January 2011, 11:20
First make sure your central widget is using layouts properly. Then put it into the main window (if you really need a main window) and set the main window layout's size constraint (not size policy of any of the widgets) to QLayout::SetFixedSize (or SetMinimumSize).

What layout should be assinged to central frame?


size policy is only relevant for widgets inside layouts. Your main window is not inside a layout. Furthermore your frame doesn't have a layout attached so it's sizeHint is practically 0. Hence the size of your mainwindow content is also 0. Why do you keep going the wrong way despite being told a couple of times how you should approach your problem? childrenRect() will likely use sizeHint() of your child widgets and since sizeHint of the frame is 0, you will get a useless output for the whole calculation. And even if not then your frame is controlled by a layout so using setGeometry() on it has no effect at all.

As far as I known, QMainWindow has its default layout management, why did you say that it's not inside a layout?

I didn't quite follow your words. I'm really confused with concept layout in Qt, and things like relationship between size policy and layout:(
Could you please explain it little more or refer me to something to read?
Thanks.

wysota
7th January 2011, 12:20
What layout should be assinged to central frame?
It depends on the contents of the frame. If it has no contents then layout is not required but you need to manually fix the size of the frame to something constant using QWidget::setFixedSize.


As far as I known, QMainWindow has its default layout management, why did you say that it's not inside a layout?
A layout of a widget is inside the widget not outside it. The main window is a floating window so it's not "in" a layout (as it would need to have a parent).


Could you please explain it little more or refer me to something to read?
Size policy is a set of rules that are used by a layout controlling the current widget to determine how much space to give to each widget controlled by the layout. Layout controlls the widgets that are in the layout, not the one the layout is in (the parent). If a particular widget (like your main window) is not part of some layout, its size policy and its size hint are ignored. The exception is that size hint of a window is used to determine the initial size of this window.

myfifth
7th January 2011, 15:21
@wysota

I'm now much more clear.
Layout in a widget is used to control layouting of its children, and size policy defines how layout works.

In my case, I should care about how to design frame layout instead of main window. I'll try it later.

Thanks a lot.

myfifth
10th January 2011, 06:18
@wysota
Sorry for late reply.
setFixedSize and setSizeConstraint worked quite well. I simply set both of them to expected values, finally it rocked.

Really thx.