Why has my QWidget stopped expanding to fit its children? - qt

Here is a screenshot of my Qt application. I have blurred everything which isn't important. Look at the bottom-right.
That "Comment" bit is a QGroupBox containing a QTextEdit, it is being cropped because some containing QWidget is not expanding to fit it.
So far I have seen widgets expand by default to fit their contents (as long as child widgets are added to layouts before they become visible, which is what's happening here) but suddenly this is no longer happening. If I manually expand the window, the "Comment" box is laid out as expected.
The innermost QTextEdit has setMinimumHeight called and I have verified that every widget in the hierarchy has QSizePolicy::GrowFlag set in its sizePolicy. I have grepped the source to check that I am not setting maximum sizes anywhere in the application. And, yes, the QTextEdit is in the layout of the QGroupBox.
It seems like Qt is saying "I'll automatically expand the main window to fit the contents, but only up to a limit."
Why is this happening and how do I stop it? Or rather, how do I make it continue the helpful auto-resizing behaviour regardless of the size/depth of child widgets?

Related

Resizing Layout equal to MainWindow

When I run my program it will display all content properly, and when I resizing the main window, the layout along with all associated widgets remain fixed, rather than resizing with the main window. I used to increase my all widget and listWidget respect to window computer resolution size but still this not one work properly.
I used this one code finding the system height and width.
QWidget widget;
widget.resize(widget.width(), widget.minimumHeight());
QRect rec = QApplication::desktop()->screenGeometry();
int h = rec.height();
int w = rec.width();
// Increasing the listwidget size
ui->listWidget->setFixedHeight(h);
ui->listWidget->setFixedWidth(w);
//increasing the button size
ui->pushButton->setFixedHeight(h0.2);
ui->pushButton->setFixedWidth(w0.2);
At this link you will find two screenshots that illustrate my problem.
Please resolve to solve my problem. Thanks very much in advance.
When defining the layout of your windows and forms in Qt Designer you have to define each element of your form in advance, in order to have a working layout.
This solution is based on the screenshots provided in the comments to the question. Follow these steps:
Add an empty widget to the central area of your form, if there is nothing there. It will be used as a placeholder for the controls you will add later, and of course you can replace it with whatever widget you want. But you need it there to define a proper layout.
In the property panel, set the horizontal QSizePolicy of this widget to MinimumExpanding.
Add an horizontal spacer to the left side of your progress bar.
Define a minimum/maximum width for the white widget on the left (I guess it's a text area). As an example set the maximum width to 200
pixels.
Make the same for the QTabWidget on the right.
Give a minimum height to the Groupbox on top.
Then give the grid layout to the MainWindow.
You should get something similar in the designer view (I use a dark theme, yours will have different colors of course):
If you complete all steps you should have a nicely resizing window.
For the future: remember to integrally define your layouts, also using placeholder widgets when needed, read carefully the documentation about the widgets size policies (there are several, you need to play with them to fully understand each one) and keep in mind that Qt uses a container based approach which is different, as an example from those used by the .Net framework that relies on the concept of anchors.
EDIT : to answer questions in the comments
You will need to add a layout to any widget that contains other widgets, e.g. adding controls to your groupbox will require to give it a grid, horizontal or vertical layout in order to scale nicely on resize. Again use spacers and size policies to make it look the way you want. If you need to add or remove controls, or change their positions, you may need to brake the layout, rearrange and then set it again.
You can also select groups of widgets and give them a layout e.g. vertical, than another group and set them horizontal and so on... then give a grid layout to the container widget to build a compound layout.
There are endless possibilities, you just need to practice and go through trial and error as for everything else...
You can also do it all programmatically, check the Qt widgets documentation for this. But for complex layouts I would not go that way: it's a lot of code... and you have to compile and run to test every modification.
Using the QtCreator, within the designer you can simply right-click on the parent-widget and add a Grid-Layout.
This one resizes it's children to it's dimensions.

How to set the desired size of a QMainWindow with QScrollArea?

I am working on a project where I have to display a pretty large (vertically) main Widget.
In the initial Version of my GUI it was just added as the central Widget of a QMainWindow, which caused the Problem that on small screen resolutions the controls on the Bottom of the Widget are unreachable.
To solve this i wrapped a QScrollArea around the main Widget, but now the main window is always relatively small even if it doesn't have to.
What do i need to change so the Main Windows (vertical) size is large enough to show all the contents unless it would be too large for the screen resolution? Also I don't want it to be stretched, so simply always using the whole vertical screen resolution is not an option. Ideally the size should be fixed to the size needed by the contents (w/o the scroll area) and only smaller where needed.
Overriding the sizeHint method did only resulted in a small enlargement of the Window and setting the minimal height brings me back to the beginning where some of the controls are not assessable on small resolutions.
Since i am new to QT I am actually out of ideas how to google the solution because most Solutions I can find are about sizing components inside a Window and not the Window itself.
By default a QScrollArea will not attempt to expand to fit its contents. In order to do this you will need to re-implement QScrollArea's sizeHint() to return the size of QScrollArea's child widgets.
In your question it sounds like you were trying to re-implement MainWindow's sizeHint? re-implementing sizeHint on the top-level window will have no effect as sizeHint designed for use with widgets inside layouts.

Centering a QDialog relative to its parent while using RestoreGeometry()

I have a program that has several QDialogs. Most are a fixed size, but one is a resizable editor. The editor dialog gets its geometry restored from a QByteArray.
The problem I'm having is the Editor is not being centered correctly. (only the window's x/y dimensions) The Editor usually appears in the upper left corner when it is instantiated.
The Editor class gets instantiated like this in MainWindow:
Editor e(this);
e.exec();
For some reason, restoring the window geometry breaks the Editor's automatic centering relative to its parent. Before I implemented the SaveGeometry and RestoreGeomentry code today, the editor worked fine.
Here's the SaveGeometry code in Editor.cpp: (it gets executed right before the current Editor object is destroyed)
// Remember current window size
QByteArray geo=saveGeometry();
SettingsManager s;
s.SaveEditorSize(geo);
Here's the restore code in Editor.cpp: (this is part of a function that sets up the UI, assigns a layout, etc.)
if(!Buffer::editor_geometry.isEmpty()){
restoreGeometry(Buffer::editor_geometry);
}
Does anyone know what the problem is?
Edit: Actually, it does remember where it was last time, it just won't center.
Actually, I think I've solved this.
Instead of storing the entire window geometry, I tried storing just the size as a QSize. The size is then reapplied through QDialog::Resize() when the Editor is initialized. The window remembers its previous size and remains centered to parent like it is supposed to.

Qt: How to resize a window to its new content

I have a window containing a QScrollArea with a couple widgets in it.
Until now, I was creating the QScrollArea and its child widgets in the constructor of my window, and then I was resizing the window vertically to fit its content using resize(400, sizeHint().height()). So far, so good.
Now, I'm adding or removing widgets in the QScrollArea at runtime. What should I do, after having added or removed widgets, to make the window fits its content vertically? Should I call adjustSize()? resize(sizeHint())? Should there be a call to layout->activate() or maybe updateGeometry() first? Which size policies actually matter in this case? The ones of the window, or of the scroll area, or both? I tried to set them all to Expanding.
I'm using Qt 4.6 on Windows.
It seems that calling resize(sizeHint()) (without any other magic) after widgets were added to the scroll area actually does the trick. Somehow missed that the first time.

Resizing QT's QTextEdit to Match Text Height: maximumViewportSize()

I am trying to use a QTextEdit widget inside of a form containing several QT widgets. The form itself sits inside a QScrollArea that is the central widget for a window. My intent is that any necessary scrolling will take place in the main QScrollArea (rather than inside any widgets), and any widgets inside will automatically resize their height to hold their contents.
I have tried to implement the automatic resizing of height with a QTextEdit, but have run into an odd issue. I created a sub-class of QTextEdit and reimplemented sizeHint() like this:
QSize OperationEditor::sizeHint() const {
QSize sizehint = QTextBrowser::sizeHint();
sizehint.setHeight(this->fitted_height);
return sizehint;
}
this->fitted_height is kept up-to-date via this slot that is wired to the QTextEdit's "contentsChanged()" signal:
void OperationEditor::fitHeightToDocument() {
this->document()->setTextWidth(this->viewport()->width());
QSize document_size(this->document()->size().toSize());
this->fitted_height = document_size.height();
this->updateGeometry();
}
The size policy of the QTextEdit sub-class is:
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
I took this approach after reading this post.
Here is my problem:
As the QTextEdit gradually resizes to fill the window, it stops getting larger and starts scrolling within the QTextEdit, no matter what height is returned from sizeHint(). If I initially have sizeHint() return some large constant number, then the QTextEdit is very big and is contained nicely within the outer QScrollArea, as one would expect. However, if sizeHint gradually adjusts the size of the QTextEdit rather than just making it really big to start, then it tops out when it fills the current window and starts scrolling instead of growing.
I have traced this problem to be that, no matter what my sizeHint() returns, it will never resize the QTextEdit larger than the value returned from maximumViewportSize(), which is inherited from QAbstractScrollArea. Note that this is not the same number as viewport()->maximumSize(). I am unable to figure out how to set that value.
Looking at QT's source code, maximumViewportSize() is returning "the size of the viewport as if the scroll bars had no valid scrolling range." This value is basically computed as the current size of the widget minus (2 * frameWidth + margins) plus any scrollbar widths/heights. This does not make a lot of sense to me, and it's not clear to me why that number would be used anywhere in a way that supercede's the sub-class's sizeHint() implementation. Also, it does seem odd that the single "frameWidth" integer is used in computing both the width and the height.
Can anyone please shed some light on this? I suspect that my poor understanding of QT's layout engine is to blame here.
Edit: after initially posting this, I had the idea to reimplement maximumViewportSize() to return the same thing as sizeHint(). Unfortunately, this did not work as I still have the same problem.
I have solved this issue. There were 2 things that I had to do to get it to work:
Walk up the widget hierarchy and make sure all the size policies made sense to ensure that if any child widget wanted to be big/small, then the parent widget would want to be the same thing.
This is the main source of the fix. It turns out that since the QTextEdit is inside a QFrame that is the main widget in a QScrollArea, the QScrollArea has a constraint that it will not resize the internal widget unless the "widgetResizable" property is true. The documentation for that is here: http://doc.qt.io/qt-4.8/qscrollarea.html#widgetResizable-prop. The documentation was not clear to me until I played around with this setting and got it to work. From the docs, it seems that this property only deals with times where the main scroll area wants to resize a widget (i.e. from parent to child). It actually means that if the main widget in the scroll area wants to ever resize (i.e. child to parent), then this setting has to be set to true.
So, the moral of the story is that the QTextEdit code was correct in overriding sizeHint, but the QScrollArea was ignoring the value returned from the main frame's sizeHint.
Yay! It Works!
You may try setting minimumSize property of the QTextEdit to see if that force the layout to grow.
I don't understand most of Qt's layout scheme but setting minimum and maximum size pretty much does what I want it to do. Well, most of the time anyways.

Resources