Qt - dynamically add QLineEdit in a panel - c++

this is a question for programming with Qt/C++. I have a combo box with two items. If current index for selection is 0, then no QLineEdit should be displayed in layout below the combo box. If it is 1, a QLineEdit should appear. It should disappear again if index is 0 again.
Notably, other elements in the layout should not be affected by the change. Values already entered by user in other QineEdit should remain in place.
Is it possible to dynamically modify widget? How did you procede?
Kind regards.

All QWidget objects have a function called hide().
You can attach a signal to the currentIndexChanged signal of the combo box, and in that function you implement whatever logic you have in mind and invoke the method hide of your QLineEdit.
The only problem with this approach is that a Qt Widget, when hidden, doesn't occupy any space on the screen, and this can lead to layout changes (depending on how you've programmed your layout, some other widgets can move a bit, for example). To prevent that you can make another Widget appear where the QLineEdit were (perhaps invoking the show() function, and placing the 'placeholder' on the same container that the LineEdit was), only to occupy its space and keep it there, or you can use a QStackedWidget add the two Widgets there and change its index.
I would recommend that you read the following example, it has some useful insight on dynamically changing things: Qt Extension Example.
Also, when in doubt, take a look in the other examples, they are really well documented and cover a lot of important topics on Qt.
Good luck with your code :)

Related

some blank space remains in QVBoxLayout after hiding widgets (Qt)

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.

QWidget Transformation

I am writing an application using Qt and would like to have a "Metro Style" interface. Everything is finished except I don't know how to make the widget appear and disappear. For instance, in WPF you can animate (UIElement.RenderTransform).(TranslateTransform.Y) so that Y becomes zero or negative. How can I move the QWidget in a QGridLayout so that it can hide?
Example:
After doing some research I figured out a way to do this. Instead of letting Qt do the layout I simply handled it myself via move and set width/height functions. Overriding resizeEvent made it so I could update the values in case the window was resized. Additionally I used setMask to ensure that the widget did not leak over to unwanted locations in the UI.

QT Unable to use an autosize QLineEdit & Layout

I have created a custom widget extending QLineEdit. I want this is 'autosize'. Ok I get it using
connect(this,SIGNAL(textChanged(QString)), this, SLOT(resizeLineEditToContents()));
I have 2 of this widgets. The idea is that a resize of widget 1 is used by the horizontal layout where I have placed the two widgets to place rightly the widget 2.
But it is impossible, I have played with all the policy possible value, without success.
The layout tries always to adjust the size of my QLineEdit widget .... (It happens also with a standard QLineEdit).
Any help?
Thanks
Actually, it's not necessary to have the signature of signals and slots to be the same, and Qt actually asks in the documentation to not put 'const' and '&' on it because of the 'normalization'. a Signal can have zero to N parameters, a slot can bave zero to Signal-Number-Of-Parameters, so that's why the connect works.
but back to your problem, you need to use setFixedWidth, so it will know to not resize back to the old width just as soon as you stretch it, then set Layout to prefered, so it will respect your widget's hints.

Sortable QHBoxLayout

I'm using Qt to create a sortable bar graph-like widget. The widget is laid out with a QHBoxLayout for each bar in the graph (which are also widgets).
When the user changes the sorting parameters, my controller clears the layout, sorts it, and calls addWidget on every item in order. The problem I'm facing is that this list is quite large (1000+ widgets), and Qt is crawling when attempting to layout that many elements.
I've found out that each time addWidget is called, Qt will recalculate the location of every item in the QHBoxLayout and then update. This is a problem, as it performs a lot of unnecessary calculations on each LayoutItem before the one I am adding. For 1000 test items that I'm putting in, resorting takes around 30 seconds, which is obviously far too long.
Is there a better Layout type to use, or is there a faster way to add a collection of sorted widgets to a layout?
Edit:
Apparently, the issue I've been having isn't with Qt laying out each item again, but the internals of all the parenting and shenanigans that go on behind the scenes I set up a test project to add 1000 buttons to a layout, printing out a counter each time. The numbers printed out almost instantaneously, though it took that same ~30 seconds for Qt to straighten itself out. I think the problem doesn't exist only with QHBoxLayout, but with Qt's layout system in general. Looks like I'll be manually positioning widgets and bypassing a QLayout altogether. Thanks to everyone who gave their input.
From documenation of void QLayout::setEnabled(bool enable)
Enables this layout if enable is true, otherwise disables it.
An enabled layout adjusts dynamically to changes; a disabled layout acts as if it did
not exist.
By default all layouts are enabled.
What about making a Graph widget (composed of Bar (or whatever name you choose) widgets) which would contain your own QLayout subclass optimized for this task (since you have to reimplement QLayout::addItem() which is pure virtual in QLayout).
Also, be sure to check out Qwt, since it already might have implemented what you want.
Perhaps you can create a new QHBoxLayout without parent, add your widgets to this layout, and then delete the old QHBoxLayout and insert your new layout. WARNING: I did not try this.

QListWidget that resizes instead of scrolls

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.