How to properly size Qt widgets? - qt

Main Question
What is the "right" way to give your widgets default sizes and make sure they contract, expand, or remain fixed if there is additional or not enough space to accommodate them?
How I Think Qt Works
After reading the Qt documentation it seems like the sizing algorithm goes something like this...the layout begins by asking its children for their ideal size via the QWidget::sizeHint method. If the layout has additional space or not enough space then it'll determine which widgets to resize based on each widget's sizing policy (QWidget::sizePolicy), minimum size (QWidget::minimumSize), and maximum size (QWidget::maximumSize).
Why isn't there a QWidget::setSizeHint method?
If my understanding is close to being accurate then it would seem all you'd have to do is set the sizeHint, sizePolicy, maximumSize, and minimumSize on each widget and everything would just work. So why isn't there a setSizeHint method?!?!??!! Sure, every time you use a widget that provides all of the functionality you need (QTableView, QComboBox, etc) you could extend it and override a single method but that sounds absolutely ridiculous.
One of the sizing issues I'm fighting with.
I've got a QMainWindow with a QDockWidget on the left hand side. The QDockWidget has a QTableView. I'd like to have the QDockWidget/QTableView take up a "reasonable" amount of space on start up and then the user can resize it however small or large they'd like.
Unfortunately, when the application starts up it gives the QDockWidget/QTableView so little space that it requires a horizontal scroll bar. The only way I've found to force it to give it a reasonable amount of width is to set the QDockWidget's minimum width but then it prevents the user from resizing it as small as they might like to.

Why isn't there a QWidget::setSizeHint method?
In my opinion it is much better for a widget to compute its preferred size based on its content (or rules) instead of allowing the coder to set a sizeHint probably hardcoded or at least prone to errors.
I almost never had to set a size on a widget, playing with the QSizePolicy was enough. And when I needed some specific constraints, playing with minimum/maximum sizes was enough. So that Qt layouts were always able to adapt the widget.
If you want to set up yourself some percentages on the sizes etc, you can play with the stretch parameter. You can also add spacers when you need empty spaces.
Extending a QWidget to override the QWidget::sizeHint method does not sound ridiculous to me, as you change the widget behaviour by changing its preferred size and that fits the polymorphism spirit of OOD.
How to properly size Qt widgets? is a vague question and depends on the use cases. Most of the time choosing the good layouts and size-policy lets you achieve very adaptative GUI. Qt Designer can help to do this right, even if the layout management is not always intuitive (you need to place your widgets first and then set them in layouts from the inner to the outer layout).
About your specific issue, it's hard to tell why your QDockWidget gets too small without knowing the details of the layout(s) you have around your two widgets in the window. Maybe it is a specific issue with QDockWidget : see related questions :
QDockWidget starting size
Qt 5.7 QDockWidget default size
Prevent QDockWidget autosizing behaviour

Related

QSplitter Stretching Factors behave differnt from normal ones

I want to create a flexible layout, where the User can resize Widgets, but still give a good default layout. I'm using the Qt Designer for everything.
As a minimal example I used a simple Windows with a Widget and a plainTextEdit. The later one seems to cause the problems, which is why I choose it. At first I built it without the Splitter which worked just fine. The Stretching factors are 1:1 by the way.
Now I put both widgets in a Splitter (by breaking the main layout, putting both widgets in a Splitter and setting a new layout to the main widget). Resizing still works but the stretching factors behave weird:
The PlainTextEdit seems to take up far to much space. The Stretching Factors are still at 1:1. I found a workaournd, by changing the stretching of the upper widget to a much higher value (in this case 9:1), which looks good again:
So my question is: Why do the stretching factors begin to behave weird when I put the images in a Splitter? And how can I solve this without using arbitrary guessed stretching factors?
QSplitter::setSizes() can be used to set relative sizes. According to the documentation, "any additional/missing space is distributed amongst the widgets according to the relative weight of the sizes".
In this case, it is a bit ugly, since you have to add this in your code rather than editing your layout in QDesigner (normally, you would want to define your layout only at one place), but still it is quick and works:
MyWindow::MyWindow(QWidget* parent):
QWidget(parent)
{
m_Ui.setupUi(this);
m_Ui.splitter->setSizes({2000, 1000, 1000});
However, I had to use big numbers (instead of {2, 1, 1}), maybe because at this point, the window is not completely set up yet (apparently, Qt is not a big fan of RAII...). Also, this kind of notation works probably only with a recent C++ version, otherwise you can also define the QList in some extra lines.

Getting QDockWidget layout right

I heavily use dock widgets to let the user arrange the tools the way she wants. Some of my dock widgets contain static controls (FS, fixed vertical size), others depict images, the larger the better (ES, expanding vertical size).
The problem I face is that I cannot get a configuration of size hints that lets me do this:
Make the variable size dockwidgets as large as possible
Let all dockwidgets tab with each other without buggy behavior
For 1., I can set the Vertical Policy of all FS's content widgets to "Fixed". This will force the container to use all free space for variable size widgets. However, as soon as a ES widget is tabbed with a FS widget, while the FS widget is not shown, I get stubborn behavior at best (user cannot adjust size) and buggy behavior at worst (when adjusting size, drawing errors happen, actual size did not change).
For 2., I can set all Vertical Policies to either "Preferred" (FS) or "Expanding" (ES). This should give preference to the ES, but it doesn't. I also tried playing with Vertical Stretch to no advance (while it is helpful in other scenarios where no DockWidgets are involved).
I am stuck with a situation where by default, the application wastes space and the user has to do several adjustments to the dockwidget sizes whenever the window size/layout changes. It is very tedious and counter-intuitive.
How do I do this right?
And a follow-up question: How to teach a DockWidget that it's contents have a specific aspect ratio?
I found the biggest issue was that I used custom widgets for display which would not overload the virtual QSize sizeHint() const method.
Overloading this method and returning a high number, e.g. 500, for the vertical size, helped the layout considerably.
It seems that the (private API) QMainWindowLayout does an initial guess on best dock widget sizes and then sticks to that. In the same course, it seems to ignore the differences between Preferred and Expanding policies or Stretch settings.
By providing a large sizeHint the custom widget gets better balance with stock Qt Widgets (e.g. QListView) that do the same.
The result is acceptable, but far from perfect.

Fixing sizes of widgets in QT designer layouts

I have a QT form that has literally hundreds of widgets and to make them all fit on the screen at once (as required) I need to make them pretty small. The Form will have fixed (non resizable) size when used. I can resize the widgets to the desired height/width and use the appropriate (small) font size, make their size policy "fixed" etc. However, as soon as I start putting them into layouts, they gow to some, much larger minimum size. This is particularly true for the height of the widgets, but width is sometimes affectged as well.
My problem would be solved if I knew how to do one of the three following things:
Change a layout's default minimum size(s) for widgets.
Force a layout not to alter widgets sizes.
Use Qt designer to nicely align widgets in grid-like formats without using layouts.
I searched extensively Qt designer's docs and SO, to no avail.
Help is greatly appreciated
Use layouts with QWidget::setFixedSize in code (or alternative you can set the fixed size policy for each widget in designer) or you can use QLayout::setSizeConstraint

Resolution handling in QMainWindow

I've a QMainWwindow, and I've fixed its size.
i.e. I've set Minimum and maximum size of the window to the same number.
Could anyone tell me whether this will be a problem if I'm to use this in another screen with a different resolution, and if so, how am I to handle it?
Kindly advise, and also if there's another way ( perhaps more elegant) to set the size of the QMainWindow.
UPDATE :
I have a QMainWindow with a QTableView as a widget, amongst others. When I expand the main Window, the tableview does not, and it leaves an ungainly blank space, so I fixed the size.
If I were to make it resizeable, how do I expand the QTableView widget, alongwith the QMainWindow. I have a Central Widget, this widget has a vertical box layout, and to this layout I've added the 3 widgets, one with QGridlayout, one horizontal line, and the other QTableView. The QTableView, on its own, is not inside a layout.
I'd imagined this would be sufficient to expand the table too, once QMainWindow were expanded, or reduced, but it doesn't happen.
How do i go about it, i.e., expanding the QTableView as well?
Thanks.
It will be a problem if you fix the size to one that is larger than the screen can handle. There are various ways to scale the size of a window according to the screen size. I recommend using QApplication::desktop(), which will return the desktop widget (you may need to #include <QDesktopWidget>. Note that this widget can actually encompass multiple screens, so if you just want the current screen, you can just do:
QRect screenGeometry = QApplication::desktop()->screenGeometry();
You could alternatively use QDesktopWidget::availableGeometry().
It is worth mentioning that among Qt users, I think there is a general dislike of fixed size windows. Most recommend taking full advantage of the Qt layout system, which provides lots of flexibility for resizing windows. I'm not saying you should definitely do this, because all projects are different, but it could be worth looking into.

Understanding form layout mechanisms in Qt

Qt has a flexible and powerful layout mechanism to handle view of desktop application's windows.
But it is so flexible, that it nearly cannot be understood, when something goes wrong and needs fine tuning. And so powerful, that it can beat anyone in their tries to overwhelm Qt's opinion of how form should look.
So, can anyone explain, or provide articles, or source of Qt's positioning mechanisms?
I'm trying to force the QLabel, QPushButton and QTableView, marked by trailing underscores in their names, be two times higher than QTextBrowser having verticalStretch = 1 below. How can I handle widget's height properly?
.ui file of my form on google docs. Search '____' in names, preview in QtDesigner
Layouts are actually easy to understand "I think". :)
A simple explanation of layouts can be found in the QT book "C++ Gui programming with QT 2nd edition"
What you should be aware of regarding layouts and their size policies
Most Qt widgets have a size policy. This size policy tells the system how the widget should stretch or shrink. It's got from the class QSizePolicy. A size policy has both vertical and horizontal components.
Most widgets also have a size Hint. This size hint tells the system a widgets preferred size
QSizePolicy has a stretch factor to allow widgets to grow at different rates
**I am only familiar with 4 size policies**
fixed size policy - The size of the widget is fixed and it can't be stretched. It remains at its size hint.
minimum size policy - The size hint is the smallest possible size of the widget, but it _can still_ grow bigger if necessary.
Preferred size policy - the widget can shrink or grow bigger than its size hint.
expanding size policy - the widget can shrink or grow bigger than its size hint :)
You may want to ask,
What is the difference between preferred and expanding?
**Answer:** Imagine a form with 2 widgets, one with preferred and another with expanding. Then any extra space will be given to the widget with the expanding policy. The widget with the preferred policy will remain at its size hint.
I recommend (WARNING: am not an expert :)) you buy and read through "C++ Gui programming with QT 2nd edition". I am currently reading it and it is making a lot of sense. Look at the images and see if they make some sense.
Explaining size policies
A simple example
This is a simple dialog with 2 buttons whose horizontal and vertical size policies are shown as are the horizontal and vertical stretch.
Here is the preview at its smallest size.
Here is another preview at a larger size
[EDITED: //added size hint example]
WHY YOU SHOULD CARE ABOUT SIZEHINT
You can see that every widget has a sizeHint which is vital because QT's layout system always respects the sizeHint. This is only a problem if the default size of the widget is not exactly what you want. The only way around this problem is to extend (subclass) the widget and reimplement its sizeHint() member function. An example is worth 1000 words. To save space, see my blog where there is an example project.
According to its docs:
When you add widgets to a layout, the layout process works as follows:
All the widgets will initially be allocated an amount of space in accordance with their QWidget::sizePolicy() and QWidget::sizeHint().
If any of the widgets have stretch factors set, with a value greater than zero, then they are allocated space in proportion to their stretch factor (explained below).
If any of the widgets have stretch factors set to zero they will only get more space if no other widgets want the space. Of these, space is allocated to widgets with an Expanding size policy first.
Any widgets that are allocated less space than their minimum size (or minimum size hint if no minimum size is specified) are allocated this minimum size they require. (Widgets don't have to have a minimum size or minimum size hint in which case the stretch factor is their determining factor.)
Any widgets that are allocated more space than their maximum size are allocated the maximum size space they require. (Widgets do not have to have a maximum size in which case the stretch factor is their determining factor.)
And sizeHint() is the recommended size of a QWidget, and the Layout of the widget parent will take sizeHint() and sizePolicy() into consideration to determine the space of the child widget can hold.
You can use QT Style Sheets to control the widgets height
and other properties in an easy customizable way.
http://doc.qt.io/archives/qt-4.7/stylesheet.html
As for the layouts you need to use them wisely and strongly
coupled with spacers in order to make the widgets behave
exactly the way you want them to.
http://doc.qt.io/archives/qt-4.7/designer-layouts.html

Resources