QSizePolicy true meaning, documentation and thoughts - qt

I have been now two years working deeply with Qt layout system. After this time i encountered thosand of problems with SizePolicies and Layouts. I normally found out solutions, but never really understood what i was doing.
Now i was taking some time to try to understand correctly and build a 101 GUIDE for them and never fail. I found out this piece of information in the documentation about QSizePolicy of a QWidget:
This property holds the default layout behavior of the widget
If there is a QLayout that manages this widget's children, the size
policy specified by that layout is used. If there is no such QLayout,
the result of this function is used.
I thought that if you had a QLabel, for example, and you set the policies to Horizontal Expanding, Vertical Fixed, THE LABEL itself changed that way.
But it doesn't, at all.
When reading that i see that it talks about ITS CHILDREN inside the LAYOUT. So what does it mean, then?. Nothing is inside the label, is that why it does not work?.
WHat about inserting a label inside a QFrame, and telling the frame to be Expanding... Will the QFrame expand or stretch (depending on the rest of brother widgets in the same Layout) or will the label expand or stretch, not the QFrame?
What a mess...
What about Stretching?. If you set stretching 10 when you add the widget:
layout->addwidget(label, 10, Qt::AlignHCenter);
It doesn't work either.
Stretch 0 when you add the widget means : Take the policies i told you. Default, depends on the type of widget. Button-like widgets have expanding-fixed. Box-like Expanding-Expanding...
Stretch 10 means: grow maximum.
Am i right? Well. When having a QFrame and a QLabel inside, setting Expanding, and 10 to strech to the label DOES NOT WORK.

I don't understand all of your questions, so I will only answer to those that I think i do.
I thought that if you had a QLabel, for example, and you set the policies to Horizontal Expanding, Vertical Fixed, THE LABEL itself
changed that way. But it doesn't, at all.
I don't know what that means. What is the exact behavior you're expecting and what is actually happening? Is this label in a layout? Are there any other widgets in this layout?
WHat about inserting a label inside a QFrame, and telling the frame to be Expanding...
If you set a QSizePolicy to your QFrame object and set a layout to it, this size policy might be ignored. Docs: If there is a QLayout that manages this widget's children, the size policy specified by that layout is used. If there is no such QLayout, the result of this function is used. This means that the widget's layout should manage the size of the widget. Note that it will still respect the minimum/maximum width/height values.
Stretch 10 means: grow maximum.
What makes you think that?. The stretch factor is dependent on other widgets inside the layout. Docs: Stretch factors are used to change how much space widgets are given in proportion to one another.
When having a QFrame and a QLabel inside, setting Expanding, and 10 to strech to the label DOES NOT WORK.
Does not work how? If you set stretch for QFrame to 1 and for QLabel to 10, your QLabel object should always be 10 times as wide/high(depending of your layout type) as your QFrame object. If your QFrame has a layout and it contains children, then this might not work as it would depend on the childrens size policies.

Related

How can I set a QPushButton to grow vertically?

Background: I need Command Link-like controls. Normally, I would use Qt's builtin QCommandLinkButton, but in this case I need to also support Right-to-Left layouts. Regrettably, QCommandLinkButton doesn't seem to respect Qt::RightToLeft when set explicitly via setLayoutDirection. There also doesn't seem to be a way to override the layout direction via style sheets.
I tried to work around this issue by using QPushButton: I instantiated QPushButton and replaced its contents with a custom layout containing two labels stacked vertically. This did not work because QPushButton refused to expand horizontally.
Failing to make QPushButton instances work, I decided to try sub-classing it. No matter what I tried (overriding sizeHint, setting vertical sizePolicy to expanding, resizeing explicitly, etc) the button refuses to grow more than 30 pixels high.
If I change QPushButton to QWidget, the new widget grows normally.
The question: How can I force a QPushButton to grow vertically and fit its inner widgets? If this is not possible, what are my options for a button-like widget that is both visually and behaviorally consistent with QPushButton and other "native" controls?
I managed to get the button to grow normally by setting the maximum height to 16777214 (instead of the default 16777215), and then setting the content margins of the button to 10.
Perplexingly, the default maximum height of a QPushButton should be plenty, but for some reason it refuses to grow past 30 pixels unless the maximum height is explicitly set to something else.
Place the button inside a layout and set its vertical size policy to Maximum.

Grid Layout Widget Sizing Problems

I use a Grid Layout inside my app. The grid layout I set to some fixed sizes.
myBootGridLayout->setContentsMargins(3,0,0,0);
myBootGridLayout->setRowMinimumHeight(0,25);
myBootGridLayout->setRowMinimumHeight(1,25);
myBootGridLayout->setRowMinimumHeight(2,25);
wdgBootFeatues->setFixedHeight(80);
For the QPushButton I use a size rule:
btnSelBootImagePath->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
But as you can see on the image, the ComboBox and Buttons have the same size but the LineEdit field is smaller. What I do wrong? Is there a trick to bring them on the common same size (Height) like in the QT documentation?
In case your question is to understand how to make sure that elements will have the same height, we should consider the following:
Layout might not necessarily ensure that some elements will have same height you would like, since it also relies on the size (horizontal and vertical) policy of the element in layout itself. In case you want to have QLineEdit and QPushButton instances to have the same height, you should set minimum height for each of them. Probably, it would even make sense to make the height fixed (i.e. set both minimum and maximum height to be the same values) for such elements to fit your needs, since both of these elements by default have fixed vertical size policy. This is for the reason, since most apps treat buttons and one line text fields in the same way.
In most cases, combining QVBoxLayout, QHBoxLayout and then QGridLayout is not necessary at all, since QGridLayout is much more flexible, and combines QVBoxLayout and QHBoxLayout features in a single layout under the hood at the first place, this it will probably satisfy all your needs (i.e. to represent you elements in a grid manner). Also, construction of UI elements will be slightly faster if less elements will be used.
Qt documentation might have such an effect because of the following reason - elements were tested on a different device. Qt does not try to make identical style sheets for widgets' elements across all platforms, thus visual differences will be everywhere. On some operating systems, button height is smaller than text field height by default, and this is completely normal.
One approach to make sure that size will get bigger than by default is to change size policy (vertical in your case). Code snippet changing size policy is correct basically. However, size policy is different thing than fixed height across elements. However, if your button and line edit would be in the same row, and both would have minimum expanding vertical policy, probably these elements would have the same height in that row.
Thus, probably to make sure the height of your elements remains the same is to set some minimum (and maximum as well in case vertical size policy is fixed) height through code or Qt Creator. This would be the easiest and least painful from thinking perspective approach. I am not sure if I have answered the question (it looks like that you answered yourself in your own way), but I am sure that I have introduced some thoughts that might come in handy when understanding Qt layouts.

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.

QT Layout - initial directions

I am new to QT. I'm trying to understand the layout mechanism by trying to implement this small window seen below. It has the following elements under the QWidget that's the main window:
One big QWidget that stretches on all the client area.
Two QWidget containers on the top of the window. Both should have the same height, but the right one stretches horizontally, as the window grows/shrinks.
one button container widget on the top right, with fixed height and width
Large QWidget container filling the rest of the client area, that should resize as the window resizes.
The parent window itself is resizeable.
I'm looking for hints as to what layout I should use. How do I achieve this programatically? define what stretches automatically, what stays with a fix size? and how the proportions are kept where they need to be kept.
I'd appreciate any pointer you may have.
The easiest, and IMHO best, way to accomplish this is via the QHBoxLayout and QVBoxLayouts. You can do this via the designer in QtCreator, but I find it doesn't work perfectly if you need to adapt things over time. If it's a static set of widgets, I do suggest designing it using the QtCreator designer as it'll greatly simplify your life.
If you're going to do it programatically, the main window should be set to use a QVBoxLayout and then two sub-QVBoxLayout's after that, where the bottom one is configured to take any space it can get. Then in the top QVBoxLayout, add a QHBoxLayout with your two upper components.
to set a widget to fixed size in code you call setFixedSize( int h, int w ) on the widget. To do it in Designer click on the widget and look in the property editor in the QWidget section. open the sizePolicy thingy and set horizontal and/or vertical to fixed. Then open Geometry and set the width and Height.
To make them stretch at different ratios in code you use a separate argument when using a box layout. eg layout->addWidget( button1, 1 ); layout->addWidget (button2, 2); this would cause button2 to expand at twice the rate of button1. To do this in designer, open the sizePolicy property of the widgets and set the HorizontalStrech and/or VerticalSretch. Note that the size policy needs to not be Fixed in this case for the direction you want to set the stretch on. Also it will never let a widget shrink below its minimum size (it would rather mess up the ratio than shrink something too small).

Qt QHboxLayout cell size ssues

For those of you who haven't been reading my Qt questoins, I am learning Qt for a project. I have only limited experience with GUI design at all, and not in Qt.
I've got a horizontal layout that I want to populate with some buttons. I can feed these buttons in just fine, but my formerly-square buttons are stretched horizontally to take up more space.
I want to let the layout manager determine the best way to size these buttons, but I also want their original proportions to remain intact. For instance, if I start would with 32X32 buttons that need to shrink to fit all of them in the layout, I want them to shrink proportionally so that the width to height scale is maintained. 20X20, 16X16, 12X12 would all be just fine, but 24X16 would be an example of dimensions that are unacceptable.
I've tinkered with size policies on the buttons and stretch options. I'm not seeing, even after reading the QPushButton and QHboxLayout classes how to do this. How is it accomplished?
Thanks.
As long as I understand the question correctly, I think what you want is QBoxLayout::addStretch(). This will add a spacer object that fills the unused space. So the buttons will have their ideal size and the spacer will fill the rest. You can try experimenting with this in Designer, it's easier than the write/compile/run cycle.
You should take a look at the answers to this question. This is a recap of my answer there.
You need to create a custom derivative of QLayoutItem, which overrides bool hasHeightForWidth() and int heightForWidth( int width ) to preserve the aspect ratio. You could either pass the button in and query it, or you could just set the ratio directly. You'll also need to make sure the widget() function returns a pointer to the proper button.
Once that is done, you can add a layout item to a layout in the same manner you would a widget. So when your button gets added, change it to use your custom layout item class.
I haven't actually tested any of this, so it is a theoretical solution at this point. I don't know of any way to do this solution through designer, if that was desired.

Resources