Use the same widget in two different layouts in Qt - c++

I would like to use the same widget in two different layouts in Qt. Here is my code:
QWidget *myWidget = new QWidget;
QFormLayout *layout1 = new QFormLayout;
layout1->addWidget(myWidget);
QFormLayout *layout2 = new QFormLayout;
layout2->addWidget(myWidget);
The widget is as it should in layout2 but is not visible in layout1.
A workaround would be to create two different myWidget widgets, but I would like to know if there is a better way of doing.
Why does this happen and what is the correct way of doing this?

addWidget transfers the ownership from layout1 to layout2.
Object trees are the way Qt uses to organize objects. As an example, an item that has a parent is displayed in its parent's coordinate system and is graphically clipped by its parent's boundaries.
You can try to work around the limitation, but it is not how you should use Qt and I won't suggest it.
If you need two widgets, create two widgets. That's how Qt is designed and how it should be used.
See here for further details about the Qt's objects model.

You cannot have the same object in multiple places. There is only once instance of it and it lives in only one single location. You can only have multiple references. Granted, a layout doesn't take a widget instance, but a reference (pointer) to it, but Qt's design is such that adding a widget to a layout will transfer ownership to the layout's underlying widget. And it makes sense, the two layouts may call for a different widget geometry, and how does a single widget have two geometries in the same time? Even if possible theoretically, it is not possible without abstracting the geometry away from the widget, and in Qt's case the geometry is part of the widget, so it is not possible. And that's just one of the many aspects which make such reuse/sharing challenging and not really viable.
Depending on what you want to achieve you could:
reuse GUI elements - in that case roll out YourOwnWidget : public QWidget, then you can instantiate in as many times as you want
share the same data across multiple GUI elements, in addition to the previous step, what you really want to do is put the data in a separate, non-visible object, then you can create and bind as many types and instances of GUI elements to it as you want.

You can use QGraphicsView. Define one instance of QGraphicsView and add it to layout1:
QGraphicsView *gv1 = new QGraphicsView();
layout1->addWidget(gv1);
Define another one and add it to layout2:
QGraphicsView *gv2 = new QGraphicsView();
layout2->addWidget(gv2);
QGraphicsScene *qc = new QGraphicsScene();
qc->addWidget(myWidget);
Now set scene to your QGraphicsView objects
gv1->setScene(qc);
gv2->setScene(qc);
After that you have two views containing the same widget.

Related

Qt QGraphicsScene dynamic GUI elements like containers

I'm using QGraphicsScene and I want to create gui elements.
How do I/should I create a list container i.e. inventory in a game context.
See HERE
For an example of what I mean. There is an inventory widget at the bottom that can be dynamically populated.
Are there any container classes like the standard list widgets but for QGraphicsScene instead?
Right now the only way I can see is to draw a 'rectangle' and manually draw and manage 'squares' on top of it... which wouldn't be a container.
Every QGraphicItem is effectively a container because every item can be optionally parented to a QGraphicsItem. When you do that, the parent affects all its children...if the parent is moved, the children move with it. If a transform, visibility, or opacity are set on the parent, those changes apply to the children as well.
Basically, your understanding is correct; you would create a parent QGraphicsItem that draws a container outline, and then you would have children that each draw their icons or whatever is appropriate.
Alternately, you can use widgets in a QGraphicsScene, so all of the widget-based containers are available. If that's the route you want to go, then look at the QGraphicsWidget class.
This is a complex subject, but hopefully this will get you started.

How to create QSplitter ui class via qt designer?

I am new to Qt and I need to implement a monitoring interface with the following considerations:
I have a main window, on which I should put multiple screens, qsplitter appears to be the best solution.
The interface provides user with the option of changing the number of cameras, so QSplitter should be created/re-created during run time.
The problem is that I have too many cameras to pre-define widgets for them, so I need to create QSplitter UI instances dynamically.
The problem is that I can't find QSplitter classes when using Qt Designer and creating QSplitter class programatically is not working as MainWindow has been created through Qt Designer (.ui).
I would like to hear any suggestions regarding this issue, if there are better approaches, please let me know.
In Qt Designer, the QSplitter is not a widget, but a Layout.
Select the widgets you want to include in the two splitter areas, then select Layout from the context menu (right mouse button) - you will find two entries Layout Horizontally in splitter and Layout Vertically in splitter to group the widgets in a vertical or in a horizontal splitter.
QSplitter isn't a strict UI element, it's essentially a parent element that controls child elements. If you want to do it through Designer you'd probably run into headaches, but the basic gist is you select a number of widgets to be controlled by it, and click the Layout Horizontally/Vertically in splitter button which is in the layout buttons group.
What you might be best doing is creating your child elements programmatically, creating your splitter programmatically, adding the child widgets with someSplitter->addWidget(...). In the Qt docs there's some sample code for this:
QSplitter *splitter = new QSplitter(parent);
QListView *listview = new QListView;
QTreeView *treeview = new QTreeView;
QTextEdit *textedit = new QTextEdit;
splitter->addWidget(listview);
splitter->addWidget(treeview);
splitter->addWidget(textedit);
http://doc.qt.io/qt-5/qsplitter.html#details
And if you really want to do it in Designer there's a guide here: http://www.bogotobogo.com/Qt/Qt5_Splitter.php
Although QSplitter is a widget, you can't create one directly in Qt Designer. It is only available for laying out pre-existing widgets - which does not fit your use-case, since you need to create child widgets dynamically.
However, you can work around this limitation by using widget promotion. This is a simple mechanism that allows you to add substitute classes to represent widgets that are not directly available in Qt Designer. The idea is that you add a widget that is most similar to the one you actually want (e.g. a QFrame is most similar to QSplitter) and then promote that to the substitute class which you have defined in your own header file. When uic finally generates the code, it will use your substitute class instead of the class of the widget added in Qt Designer (which just acts as a placeholder).
Note that when you create your substitute class in the Promoted Widgets dialog, the base class should be a QFrame, not a QSplitter. This is because you are extending a QFrame (i.e. your placeholder widget), rather than a QSplitter. Of course, you can define your substitute class to be anything you like.
Image is easier to understand.

Is there a away to merge a QGridLayout of a child widget in the QGridLayout of the parent dialog?

When writing grid-like dialogs I often happen to need multiple columns having the same structure, with the number of columns known only at runtime (think configuration parameters for multiple instances of the same kind of object).
In this situation, the regular Qt widgets designer falls short, because, although I can comfortably design the various headers and a "prototype column", there is no easy way to replicate the creation of such column at runtime (all the widgets are created together in setupUi, and there's no easy way to clone QWidgets).
An alternative may be to split up the "prototype column" in a separate custom widget (that aligns the child widgets using a QVBoxLayout) and instantiate such custom widget at runtime in the parent dialog, putting those instances in a QHBoxLayout.
The problem with this approach is that the widgets of different columns may end up horizontally unaligned, as each QVBoxLayout performs its calculations on its own without considering the other columns, so the desired grid layout is easily messed up.
The only other possibility that comes to mind would be to split up the prototype column in a separate widget as described but, instead of putting the custom widget in a QHBoxLayout, "stealing" its children and putting them correctly aligned in the parent QGridLayout. This results in the desired graphical effect, but reparenting the children and hiding the custom widget feels a bit like a hack.
Now, my question is twofold:
are there potential issues I may be unaware of in happily reparenting such children widgets, given that their "fake" container isn't going to do anything particular with them?
are there better approaches to this issue? Ideally I would think about some method to merge QGridLayout of children widgets with a "main" grid, but there seems not to be such a thing.

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.

How should I use a QGraphicsScene with layouts and widgets

I'm creating some graphic data displaying widget in Qt4 and I was tempted to use the QGraphicsScene for it, create QGraphicsItems for the data items etc.
However, I wanted to add some layer of controls (eg. scrollbars, zoom+other buttons - I want to make it in a similar style as eg. Google Maps, that is, the data would be displayed all over the widget, and the buttons would be shown atop of them) to the widget. So I thought it might be feasible to add them to the scene (perhaps as a child of a QGraphicsGroupItem that would be shown over the data). But I want them to move & resize when I resize the whole widget, so I should use a QGraphicsLayout for managing them. But at this point, I discovered things are pretty complicated.
The problem is that when using QGraphicsLayout, the following constraints hold:
Only a QGraphicsWidget can be managed by a layout
QGraphicsLayout can only be used to manage children of a QGraphicsWidget
Which means that I would have to create my controls as QGraphicsWidgets, add a top level QGraphicsWidget to the data widget, and manage the size of this top level widget myself.
So I want to ask:
Wouldn't a classic approach (ie. use plain old widgets for all controls, and use QGraphicsScene only for displaying the data) be more reasonable?
Is there any advantage in using QGraphicsScene in this case (performance or simplicity...)?
How should I use QGraphicsScene to exploit its strengths?
Since Qt 4.4 you can embed classic widgets in a QGraphicsScene by using QGraphicsProxyWidget :
QWidget *widget = new QWidget;
QGraphicsScene scene;
QGraphicsProxyWidget *proxy = scene.addWidget(widget);
If you think that QGraphicsScene (or whatever other widget you have) is appropriate for most of your display, use that. What we have done in the past for somewhat similar things is to make a custom widget that inherits (one way or another) from QWidget, and put the control widgets in a layout on top of that widget. This means that the whole widget is drawing whatever it is you want drawn, and the control widgets are on top of that, resizing as the whole widget is resized.
Alternatively, a couple of times we've had layouts that were just a bit too complicated for the layout widgets to easily handle. Rather than create a custom layout, we just positioned them with no layout, and moved them in code on the resize event. It works just as well.