Z-Order for QML component loaded from C++
-
I am loading a 'secondary' QML file from C++ and put its contents in between the contents from the main QML file like this (with increasing z-order, m means main, s means secondary): Page (m)/Cont (s)/Cont (m).
When doing this using a Loader item, I can control the z-order nicely by setting the z-order of the loader:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Page { id: page objectName: "Page" anchors.fill: parent Loader { id: pageLoader z: 1 } Button { id: button objectName: "Button" anchors.fill: parent onClicked: pageLoader.source = "green.qml" } Rectangle { id: rect1 color: "Red" x: 0 y: 0 width: 100 height: 100 z: 2 } Rectangle { id: rect2 color: "Blue" x: 25 y: 25 width: 100 height: 100 } } }
The green rectangle from green.qml will appear in between the red and the blue rectangle.
import QtQuick 2.0 Rectangle { id: rect3 color: "Green" x: 50 y: 50 width: 100 height: 100 }
If I do the same without Loader, but from C++, the green rectangle always appears on top. Setting its z-order does not have the effect I want. Here is the code which I am using for loading the QML and setting z:
void on_clicked() { component_.loadUrl(QUrl("qrc:/green.qml")); QObject* view(component_.create()); QQuickItem* item = qobject_cast<QQuickItem*>(view); QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); item->setParentItem(parent_); item->setZ(0); view->setParent(&engine_); }
The variable parent_ has been set to the Page item in the main QML.
No matter which positive value I am using in the call to setZ, the result is always the same (green on top). With a negative value, the green rectangle disappears, because it is hidden by the button which covers the entire page.How can I successfully put the green rectangle in between the red and the blue one using C++?
-
Many thanks for this. Would you recommend me going the Widget way and use UI files instead, because, I am afraid, the basic architecture of my applications is given.
@HJPVVV said in Z-Order for QML component loaded from C++:
Many thanks for this. Would you recommend me going the Widget way and use UI files instead, because, I am afraid, the basic architecture of my applications is given.
No, ideally you should have the same separation in Widgets as in QML. The fact is that's easier to mix business and ui layer when using Widgets, but that doesn't equal good code.
You can still do what you want in QML.
Sorry for missing your paragraph about how you set_parent
.In your case your problem is that your items declared in QML are parented implicitely parent to the Page's
contentItem
not the page itself. So what you what is setParentItem to the contentItem of the Page. -
What is
parent_
in your c++ code?Note that dynamically instantiating a QML component apart from the main one seems like a code smell to me.
I would connect to a c++ signal in QML and instantiate a "dialog" directly from QML, the c++ business side shouldn't be aware of the UI layer. My 2 cents. -
Quoting the question: "The variable parent_ has been set to the Page item in the main QML."
Justifying my question: For my set of applications, I want to provide a main view which only provides navigation means using semi-transparent buttons.
The actual content is displayed by views which are loaded dynamically. Several views can be displayed side-by-side in a sort of tableau-style. This process is entirely handled by a separate C++-framework. When a tableau is selected, the views it contains should slip in z-order between the parent Page item which constitutes the container and the navigation items.Short version of my question: why does item->setZ(0); have no effect?
I actually think, that the call should not be necessary at all because rect1 has been given a z-order of 1, so the dynamically created rect3 should be put on top of rect2 but below rect1. -
I know that it is possible from QML, I already tried that successfully. In my justification I tried to explain why I want to do it from C++. I would really appreciate substantial answers. Whenever I asked about QML/C++ so far, I have received similar answers: just do it in QML. So I am beginning to doubt whether my plan to achieve a strict separation between layout/appearance and functionality by using QML/C++ was a good idea.
-
We understand you want a separation of concerns. We are telling you that the design of QML draws the line of this separation at a different point than you are imagining. QML is responsible for displaying data driven by C++. It is also responsible for controlling which views are available in response to events from C++. This is why QML has loaders, dynamic object creation, etc. The business logic can be safely tucked in the C++ side. This allows the the QML side to even potentially NOT EXIST and the C++ side can still do its thing. You are trying to put the logic of the QML object creation on the C++ side. This is only going to create pain down the road.
-
Many thanks for this. Would you recommend me going the Widget way and use UI files instead, because, I am afraid, the basic architecture of my applications is given.
-
Many thanks for this. Would you recommend me going the Widget way and use UI files instead, because, I am afraid, the basic architecture of my applications is given.
@HJPVVV said in Z-Order for QML component loaded from C++:
Many thanks for this. Would you recommend me going the Widget way and use UI files instead, because, I am afraid, the basic architecture of my applications is given.
No, ideally you should have the same separation in Widgets as in QML. The fact is that's easier to mix business and ui layer when using Widgets, but that doesn't equal good code.
You can still do what you want in QML.
Sorry for missing your paragraph about how you set_parent
.In your case your problem is that your items declared in QML are parented implicitely parent to the Page's
contentItem
not the page itself. So what you what is setParentItem to the contentItem of the Page. -
@GreckKo Thank you for your answer and sorry for the (announced) break. I tried your solution and it worked. Hint: since the QQuickItem class has no member contentItem(), I used the following code:
qobject_cast<QQuickItem*>(rootObjects[0]->findChild<QObject*>("Page"))->childItems().first()
to get the content item.