QWidget's minimumSize vs minimumSizeHint - qt

Qt's widgets have 2 properties determining how small they can be:
minimumSizeHint
minimumSize
Now their basic difference seems clear enough: minimumSize restricts what size the widget can actually have, and Qt won't allow setting the size smaller. It also overrides minimumSizeHint, if set. And then minimumSizeHint is only used by layouts, which won't resize the widget smaller than that when resizing its contents.
Now I was implementing a custom widget, no problems there, and I started wondering about this.
Question: why would you ever want to use mininumSizeHint at all? What is the scenario, where you have to, or want to use it instead of just always using minimumSize? Why does minimumSizeHint exist?
(And if answer is "yeah, sizeHint is enough for everything", that's fine.)

I think the main difference is that minimumSize can be changed by any other object at any time, whether you like it or not, as all QWidgets have a public setMinimumSize() function; whereas your widget alone controls what is returned by minimumSizeHint().
As an implementer of a custom widget, you always want to override minimumSizeHint() if your widget has a minimum size that you think should usually be respected. This is what the built-in Qt widgets do.

Related

Move splitters in design mode

When i add splitters, it acts as a layout, but also allows to resize the widgets in runtime. So, for example, i managed to lay out my widgets in this way:
Therefore, i can resize my widgets in runtime. As i noticed, this function is also available in designer mode, but it doesn't work properly. I tried to hover over my splitter and drag it in designer mode, but it only replaces the entire widget.
That is how does my main window look like in QtDesigner. I haven't tried to code yet. The problem is, that even though i used to set a stretch factor, my widegt's look in designer mode and in runtime completely differ. They have another sizes.
So, what are the problems:
Firstly, i can't change my widgets sizes properly, using stretch factors. I don't know, i tried to change size policies, but i did't manage to see an effect. I have somehow changed size of the vertically oriented widgets, but when speak about horizontal orientation - stretch factor and size policy doesn't change anything at all.
Secondly, i can't move my splitter in designer mode. It's position is constant, by default, it's always somewhere in the middle.
Thirdly, i have bugs (i think so) with my widget sizes in designer mode. They differ with widget's sizes in runtime.
Question:
So, how can i change widget's sizes properly? Maybe there's a way of moving a splitter in designer mode - do newer versions of Qt have it? Currently i'm using Qt 5.9.9. Also, why these bugs, and are they bugs at all. Maybe i just should update my Qt to newer versions to get access to newer functionalities?
Comment: I'm not sure if stretch factors work with layout as they do with widgets. I'm using layouts exactly the same way i use widgets. My layout's wrong(maybe) use may have caused this problem. Anyways, i'm entirely new to Qt, and may not know something to understand it completely.

How to properly size Qt widgets?

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

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.

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.

QGraphicsWidget vs. QGraphicsLayoutItem

I'm working with QGraphicsView/Scene for the first time. This is in PyQt, but except for the fact that Python is different with multiple inheritance, I think this is a generic Qt question.
I started out by creating a couple of QGraphicsItem overloads as building blocks. Once I had those working the way I wanted, I wanted to try to combine them and was unpleasantly surprised to find that I couldn't use the in QGraphicsLayouts. This is due to the fact the QGraphicsLayouts take items that inherit from QGraphicsLayoutItem, and QGraphicsItems are inherited by QGraphicsLayoutItems, which are in turn inherited by QGraphicsWidgets.
There is a graphicsItem property of QGraphicsItem/QGraphicsWidget, but looking at the code, I don't think I can assign my Item's to this property and have them work properly. I did find this example, but strangely enough it has examples that inherit from both classes. Pretty confusing to me.
So I'm trying to find the easiest way to get my Items working in Layouts. Is there an easier way to do this than rewriting and inheriting from one of this two classes?
Secondary question, is there a rule of thumb for when you should inherit from QGraphicsWidget vs when you should inherit from QGraphicsLayoutItem?
Extra credit for explaining when sizeHint vs. boundingRect are used.
Appreciate the help,
Brett
The easiest way to get items working in layouts is to change the inheritance to QGraphicsWidget and override the setGeometry() and sizeHint() methods. Should be a simple change since your items will still be QGraphicsItems through the inheritance ancestry.
The Qt Graphics View framework is designed to be as lightweight as possible. Thus there are many choices for assembling items with different capabilities. If the sizes of items to be in layouts are not a concern, you can inherit from QGraphicsWidget. Otherwise, inherit from QGraphicsLayoutItem (unless you need the extra capabilities of QGraphicsWidget). Since you can't multiply inherit from PyQt classes, you'll have to use composition for creating an item controlled by the QGraphicsLayoutItem, like in the example you referenced.
The boundingRect() method is used by the scene to manage items. The sizeHint() method is used by the layouts to determine the size of layout items. The shape() method is used by the scene to more precisely determine the location of items (for collisions, hit tests, etc).

Resources