How to draw a QQuickItem on a QQuickItem - c++

I have two QQuickItems and I would like to draw one on top of the other in C++ before it is exposed to QML. I would like to do this because I want the second QQuickItem (which I would refer to as background QQuickItem from here on) to act as the background of the first QQuickItem (which I would refer to as parent QQuickItem from here on) and then draw a QPixmap (which has been painted on using QPainter) on top of both items. I would also prefer to pass in the second "background" QQuickItem as a property to the first QQuickItem so that it can be set dynamically from QML. Does anyone have any idea on how to do this?
I would like to mention that both QQuickItems have implementations of QQuickItem::updatePaintNode(). Is there a way to make them work together?

To do that, you have to use the visual parent property (note that in c++ you access it with setParentItem() and parentItem(), not parent() which is for the QObject parent).
If you want to have a background property, I guess you don't want to have your background as the parent of your item, so you could instead set yourself as the parent of the background and set the background's z to -1 so it paints behind your item.
Alternatively, and that's what Qt Quick Controls 2 do, you could have a QQuickItem painting nothing and just be a parent for your background and your content item (QQC2 controls expose their contentItem as a property but you don't have to).
For some inspiration you can check the source code of QQC2's Control here : https://code.woboq.org/qt5/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp.html
Don't forget to handle the resizing of your background to the size of your item.

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.

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.

Triggering PaintEvent in a "hidden" QGLWidget without a layout?

I have a QGLWidget that shares context with 5 other widgets that can change layouts and locations dynamically. This shared widget is something that I dont want to be shown because it doesnt fit in anywhere. The only way I can use it, however, is by doing a "static" one time VBO generation in its initializeGL().
How do I use its paintEvent as normal with this shared widget not being attached to a layout or visible in any way?
To make it appear seamless you attach the shared QGLWidget only onto the QMainWindow, then show() the QMainwindow so the initializeGL() gets called. Basically you show the QMainwindow earlier than normal.

Is it possible force Qt to call paintEvent after other Qt components are drawn?

I've a class that extends QWidget and contains a QLabel (lblBackground). I've overriden paintEvent function too.
I want to draw something on top of lblBackground however paintEvent method is called before the QLabel is drawn. Thus my custom drawings are overwritten.
Is there a way to change drawing order?
Painting the children on top of their parent is the common thing to do. That being said you could try one of the following options:
extend QLabel itself to paint whatever you want
try to set the Qt::WA_TranslucentBackground flag on the QLabel and having an alpha channel, so that the underlying parent (QWidget) would shine through
if you are only using the QLabel to paint some background, maybe you can get rid of it and paint the desired background first thing in the QWidget's paintEvent()?
If you want to use label as a background then just create your custom widget as a child of your label. May be split some window frame related tasks if any (to be implemented as a parent of the label) and drawing/controls/etc (to be child of the label).

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.