I have multiple widgets inside of a main window. Each widget and the main window all exist in layouts. In the case where there are two widgets next two each other is there a way to have one expand before the other expands/shrinks? I need both widgets to be expandable, but one is more important than the other. So, when the widgets shrink I need the widget on the left to shrink before the widget on the right shrinks.
This can be easily achieved by setting a non-zero stretch on the widgets, and ensuring that they report proper maximum sizes. The stretch on the more important widget can be, say, 10x that of the less important widget. That way, the less important widget will grow very little unless the more important one is at full width.
Related
There are hundreds of widgets in QVBoxLayout. I am hiding/showing them based on option menus. If I hide some of widgets, some blank space remains in QVBoxLayout and I dont want this unnecessary space. Adding spacer at bottom is not solving the issue. Same for setting margin spacing. Its like hidden widgets consume some space. Is there any way to fix this?
Thanks.
Layouts have some default spacing between each child widget, defined by setSpacing(), setHorizontalSpacing(), setVerticalSpacing(). Even if you hide the child widget, the spacing around it remains visible. (Note: I think this is a bad design decision made by Qt developers, but we need to live with it.) You have basically these options:
a) Remove the child widget from the layout instead of hiding it. Remember its original position and if it should be shown again, insert it at that position. This is complicated, the original position may be invalidated if you removed some other widgets meanhile, so this would require some clever algorithm for maintaining the correct visual positions of the hidden child widgets in the layout etc. I would not do this, feels too complicated for me.
b) Use zero-sized default spacing in the layout and add spacings manually by https://doc.qt.io/qt-5/qboxlayout.html#addSpacing and then when hiding the child widgets, set the size of the QSpacerItem next to it to zero. And set it back to non-zero when showing the child widget again.
c) Alternative to a) but do not keep original indexes but have a container of pointers to the child widgets and when a change in the visibility of the child widgets is required, then remove all the items from the layout and put all the child widgets which should be visible to the layout. This means to re-create the content of the layout in each change. Actually this is how I am doing it in my code. I have about 20 widgets and hiding/showing is fast enough. I believe it will be fast enough even for hundreds of widgets.
d) And alternative to c) ... if you have really large number of widgets, then you should consider deleting those which are not supposed to be visible and re-creating them when they are shown. I.e. in c) we keep the widget alive but hidden in a certain container but in d) we delete this widget and create it later again. It depends on your use case whether c) is better than d) or vice versa. My gut feeling is that c) should be fine performance-wise and is simpler.
Note: My reasonging is based on showing and hiding of widgets in grid layout, but I guess that VBox layout has the same principles regarding preserving default spacing even around hidden items.
I use QSplitter to place some widgets side by side.
Being a user, I can resize those widgets just dragging a splitter.
Being a programmer, I don't know how to specify exactly what width and what height do I want at the moment.
That's my original state (adjusted by different stretches).
I tried to use setFixedSize(), but after that call the user can't resize widgets by itself anymore (and that's definitely correct behavior, because the size gets 'fixed').
If I use resize(), it has almost no effect. The widget is resized, but (!) incorrectly and (!) when I start dragging again the widget gets its initial state.
Is there any way to resize that left widget in code correctly? I don't want to have fixed size but resize() doesn't work properly, as you can see. So what should I do?
QSplitter hast its method QSplitter::setSizes(QList<int>) where each entry in the list is the size of the widget in pixels, from left to right or top to bottom respectively. The method does not require you to know the exact width, it still works with guessed sizes.
I use this functionality for instance to store the user defined sizes (obtained by QSplitter::sizes()) in a QSettings instance on the program shutdown and reapply them when the software is started again. If they are not set for some reason I just set the overall width divided by the number of widgets in the splitter and it works fine enough as an initial state.
In Qt, how can I have a widget which automatically sizes itself according to the size of it's children?
For example, if I have a QGroupBox which contains a QHBoxLayout which contains some QPushButtons, I would like the QGroupBox to automatically calculate it's size so that it is no bigger and no smaller than necessary to fit all of the QPushButtons.
Ideally I would like to be able to do this in Qt Designer so that I can create a .ui file which already knows how to size the QGroupBox, however I am also opening to deriving from a class inside a .ui file and doing the resizing manually.
I have tried placing the QGroupBox inside it's own layout (with and without a spacer) but this just resizes the QGroupBox to the smallest possible size so that none of the children are visible.
There are two things to pay attention to:
Set the size policies appropriately on the children in the groupbox. You literally need to think what the buttons can do - most likely, you do not want the buttons to either grow or shrink, so setting both of their size policies to Fixed is the right thing to do. You could, possibly, let the buttons expand horizontally, so the horizontal policy of MinimumExpanding is an option.
Set the size constraint on the layout in the groupbox to act according to your objective:
ui->groupbox->layout()->setConstraint(QLayout::SetMinAndMaxSize);
Of course, the groupbox will be inside of some layout in its parent window, but that doesn't matter.
You'll probably have the most luck by sub classing QGroupBox and overriding sizeHint or other sizing functions to loop through children and calculate the minimum bounding rectangle. Depending on how dynamic the group box is, managing connections to new widgets might be a small challenge.
I have a complex layout of widgets in widgets in widgets in a QMainWindow. In one of them I have an image, it sits in the corner. What I would like to achieve is following: if the image is activated (e.g. clicked upon), it should be enlarged, so it might overlap other widgets, or parts of other widgets. The problem is, I still would like it to remain in the layout, but in a way that everything else remains in its original size and position.
I was thinking about having an empty but similar size widget as a "placeholder", and have the actual resizable widget float on top of it. My problem is, that it does not guarantee that it stays in its position if the main window is resized, maximized, etc. Is there a better or more efficient way to do it?
One way to do it, if the widgets to be overlapped are in the same layout than the one you want to enlarge, and the policies for that widget allow it, is just .setVisible(false) in the other widgets. The widget that remains visible should resize to cover all the available area!
If I can't find a better solution, I think I'll do the following:
The MainWindow will have no layout, just two QWidgets on top of each other. The bottom one will contain all the layouts and everything else, while the upper one will have a transparent background and the resizable widget, maybe supported with a number of spacers.
How do you change the behavior of a QListWidget so that it resizes its height instead of choosing a (seemingly arbitrary) height and adding scrollbars? See screenshot:
The QListView's should fill up as much space horizontally as they can (creating as many "columns," if you will.) Then they wrap and make as many rows as necessary to fit all the items. These calculations should be adjusted as the window is resized. This is all working fine.
However, what I want to happen is that instead of the height staying the same, the QListView should grow or shrink vertically and never need any scrollbars. The scrolling, if necessary, will be handled on the parent QWidget that hosts all of the labels and lists. It seems like once the height of the QListWidget is established (not sure where its default is coming from), it never changes. It is too big in some cases (see second "Test" list above) and too small in others (see first "blank maps" list above.)
The layout above is nothing surprising: two QLabel's and two QListWidget's in a QVBoxLayout. Here are the properties I have set on the QListWidget's:
setMovement(QListView::Static);
setResizeMode(QListView::Adjust);
setViewMode(QListView::IconMode);
setIconSize(QSize(128, 128));
(I already tried setting the horizontal and vertical scrollbar policies, but that just turns the scrollbars off, clipping the content. Not what I want.)
Maybe you could this without using QListWidget. The Qt's examples contain a new layout class, QFlowLayout, which could be useful. With the following kind of widget hierarchy you could get multiple groups with labels and they all would be inside one QScrollArea.
QScrollBox
QVBoxLayout
QLabel "Blank maps"
QWidget
QFlowLayout
your own widgets showing map images and labels
QLabel "Text"
QWidget
QFlowLayout
your own widgets
The problem is that this kind of solution would create much more widgets than QListWidget based solution. So if you have hundreds of items in your list, this might not be the best solution.
There is a protected member function called contentsSize() in QListView. It is used to calculate the required minimum(), maximum(), and pageStep() for the scrollbars (as mentioned here).
Can you subclass the QListView class and make use of that information? I suggest you recalculate the size of your widget in the same function where you add contents to it. While somewhat lacking elegance, this appears to be a pretty reliable solution.