Qt QGraphicsScene dynamic GUI elements like containers - c++

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.

Related

Qt Application with QTabWidget, QGraphicsScene and QPushButton

I want to create a Qt application with a QTabWidget, where each tab contains a QGraphicsView and a QGraphicsScene to draw a polygon on a Cartesian plane. example: first tab for a triangle, second for square, etc...
So, I create my qt application and then:
- inside my class derived from QDialog, I create a QVBoxLayout, I've added my widget to this, and I've inserted it into my QTabWidget, created with QDesigner: I repeat this operation for each tab of QTabWidget.
I want to know if it's a bad practice to add a QGraphicsScene into a tab in this way or to redefine all the classes from qwidget, view, and scene.
out of the QTabwidget, i have some QPushButtons that do some operations on the QGraphicsScene's polygons: when i click on a polygon, i want to do some operations through the QpushButton, like sum the angles (only on the polygon that I've clicked).
How do I communicate to the QPushButton (out of the QTabWidget) that I've clicked a polygon and which one I've clicked(inside QTabWidget)?
the private data field of my_scene contains a QList of triangles (derived from QGraphicsPolygonItem)
https://i.stack.imgur.com/Pu329.jpg
I want to know if it's a bad practice
Generally speaking no, it isn't.
If you are ok with the functionality of some class you should use this class. If you need to extend it in any way you should subclass from this class and add everything you need.
It's true not only for Qt classes but for any other classes written by you or somebody else. It's one of the basic principles of inheritance.

Use the same widget in two different layouts in Qt

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.

Select multiple QGraphicsItems without holding down key

I'm using a QGraphincsView that holds several elements which inherit from QGraphicsItem. The whole thing works fine, I can select them as desired. And when I hold down the Ctrl-key I can select several of them.
Now I want to implement an optional multi-selection without the need to hold down Ctrl-key. I already tried to set the related modifier in mouse-press-event by calling
evt->setModifiers(Qt::ControlModifier);
before the event is handed over to it's base-class QGraphicsItem but this does not work.
So my question: what has to be done to get multiple selection functionality by default and without holding down a key?
Thanks!
This is controlled by the QGraphicsScene. You stated: -
I'm using a QGraphincsView that holds several elements which inherit from QGraphicsItem
This is not actually the case. A QGraphicsView is a window into an area of the scene; it is a QGraphicsScene which holds items derived from QGraphicsItem.
You can see in the documentation that the QGraphicsScene has functions such as selectedItems(), selectionArea() and setSelectionArea(). While a QGraphicsItem can be selected with QGraphicsItem::setSelected, the control of what happens when you click an item is governed by the QGraphicsScene, with the event having been passed from the QGraphicsView.
If you inherit from QGraphicsScene, you can override the mouse methods; mousePressEvent, mouseMoveEvent, mouseReleaseEvent. This will allow you to monitor when the user selects consecutive items by clicking on them and react by calling their QGraphicsItem::setSelected function.
Alternatively, depending upon your design, you can allow the user to draw an area on the scene and call QGraphicsScene::setSelectionArea, which will set all the items surrounded by the given QPainterPath.

qt create simple rectangular board

I want to create a rectangular board using QT. This board will be updated when a step is performed. For example on step x, the text in cell 5,6 updates from "not explored" to "explored".
I have looked through the QT documentation and found the class QGraphicsView. How can i use QGraphicsItem to simulate a cell where text can be written?
I am also open for alternatives.
Technically this could also be done by customizing a QTableView/Widget, but QGraphicsScene is more robust for custom graphics and performance.
From a high level view, you can either create a composite object representing a "Cell" item, or you can subclass a QGraphicsItem and do all the custom painting yourself.
When creating a composite object, that would just be a QGraphicsItem "Cell" subclass which contains maybe a QGraphicsRectItem and a QGraphicsTextItem as members, set to the cell instance as a parent. This will keep the child items translating with the parent cell item.
When creating a completely custom QGraphicsItem, you would define all the painting inside of the paint() method, which would draw a rectangle, and text taken from a value set on the instance.

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.