Dynamic QML Page loader
-
Hi all
i am developing an application that has a lot of different pages. I don't want to create all of them as it gets started and then show only the one that is interacting with user. I would like to create and destroy QML objects as i need, creating a queue that allows me to keep trace of the pattern that the user has followed while using the software.
I have though to create a C++ object for doing it ( i will name GuiTreeManager). It will be the only component able to load / destroy the pages. I am thinking to use the QQmlApplicationEngine for loading the pages, and to expose it as a singleton for all of them. I have hence some constrains to respect:- The QML must have a Window, which allow me to use the QQmlApplicationEngine
- Expose the GuiTreeManager as singleton and connect the GUI QML events to a slot called "loadNewPage". it will have the url of the new page to be loaded as argumnet.
- All the GUI QML items must have a method that allows the GuiTreeManager to close and destroy all of them ( i want to avoid any memory leakeage). I need something similar to an interfaces, that all the QML pages must impement.
Let me pass to my questions.
-
First of all: does any other better way for doing what i need?
-
Does in QML exist something simialr to the interfaces
-
is it possible to call the destructor of a QML object?
Thanks in advance and sorry for what i am asking for. I know that it could be a very silly question?
Best Regards
Cristiano Narcisi
-
-
Thanks a lot @shaan7 . As you can understand, i am not so ecperienced with QML. I have just read something about StackView, and it seems to do what i was asking for. I am some doubt, that could be sounds very stupid for you.
How can i create nested pages using it? I have download the touch application and only the first page can load the others and only from the main page the user can go back. It is not exactly what i am meaning.
Do you understand?Let me add a snippet of code:
Item { id: element1 Loader { id: loader anchors.fill: parent } Text { id: element text: qsTr("First Element") } MouseArea { anchors.fill: parent onClicked: { loader.setSource("SecondItem.qml") loader.active = false } } }
I iwould like that loader.setSource("SecondItem.qml") will create the new page for first ,and then will destroy itself!
-
Hi,
I think there is a good example for you in the
New Project
dialog inQt Creator
-
This will give you an example app which has a
StackView
with two pages and you can navigate by using the menu or pressing Back-Let me know if the example is still not enough for you and you have any questions.
-
@CristianoNarcisiVidex perhaps my blog gives you some hints: https://appbus.wordpress.com/2016/05/27/stacked-pages-app/ (it's something outdated, but you should get the idea HowTo deal with StackView)
-
Thanks @ekkescorner !!! Your blog seems to be very interesting for my purposes. Anyway, i will try to answer either to @shaan7 . I would like to have something that doesn't need to know how the pattern is made. Let me try to explain better ( sorry but my english isn't so rich!).
Each "page" must contain a Loader object for loading another source. In this way, going back and forward becomes only a call to Loader.setsource("next_page.qml"). The only problem is that i am not still able to close the "current" page as it loads a new one. Doing this, i will have only one QML file loaded at time, reducing the resources used by my interface. I have done this long time ago using QWidget, and i would like to do the same using QML .Any hint will be really appreciate!!!
Thanks a lot
-
Ah, so you don't want
StackView
-based navigation per se. In that case, lets say you first callLoader.setSource("Page1.qml")
, theLoader
will load it and display it. Now, when you want to loadPage2
, I understand that you want to unloadPage1
to conserve resources. To do that, you can simply callLoader.setSource("Page2.qml")
and it will do exactly that - it will unloadPage1
and loadPage2
. -
Why not just use
StackView
and callreplace
when you want to change the page ? -
Ok @shaan7 !!! You are suggesting me to use one single Loader, and then each QML file that will be loaded must call it for changing the content of the page, right?
In this way i can't separate the the pages from the Loader, and i would like to separate each page from any other component as much as possible. -
@CristianoNarcisiVidex said in Dynamic QML Page loader:
In this way i can't separate the the pages from the Loader
Um, I'm not sure I understand what kind of separation you want here. No matter how you implement things, if you need some code in
Page1
to navigate toPage2
, then that code will have to callsomefunc("Page2.qml")
. When you're using a globalLoader
, its just thatsomefunc
sets theLoader
'sactive
property accordingly.As an example, lets say I call my
somefunc
asnavigate
:main.qml
:Window { width: 800 height: 600 function navigate(page) { loader.source = page + ".qml"; } Loader { id: loader anchors.fill: parent source: "Page1.qml" } }
Page1.qml
Item { id: page1 Button { text: "Next" onClicked: navigate("Page2") } }
Page2.qml
... as required ...In a different approach, I can use a
StackView
instead ofLoader
where thenavigate
will callreplace
as @GrecKo described. -
Thanks a lot @shaan7! We are about to reach a good solution. I am trying to do the same, but i would like to use Window instead of Item in QML pages. Changing this , the application gets closed after calling the setSource methods.
Is it the same to you?Thanks!
-
@CristianoNarcisiVidex said in Dynamic QML Page loader:
but i would like to use Window instead of Item in QML pages
Why would you do that? It will mean that every time user navigates to new page, a new
Window
will be shown, it might not be a good experience.About why the application gets closed, can you share a code snippet? Or even a link to a git repo works.
-
here is the main.qml, where i have the loader
Window { width: 640 height: 480 function navigate(page) { loader.setSource(page); } Loader { id: loader anchors.fill: parent source: "FirstItem.qml" } }
This is FirstItem.qml
Window{ visible: true width: 800 height: 900 color: "green" Text { id: element x: 206 y: 234 text: qsTr("First Element") horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.bold: true anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter font.pixelSize: 43 } MouseArea { anchors.fill: parent onClicked: { navigate("SecondItem.qml") } } }
And this the second
Window{ visible: true width: 640 height: 480 color: "white" Text { id: element x: 206 y: 234 text: qsTr("Second Element") horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.bold: true anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter font.pixelSize: 43 } MouseArea { anchors.fill: parent onClicked: { navigate("FirstItem.qml") } } }
-
Ah ok, the app exits because the moment your first
Window
closes (before loading the second), your app has no visibleWindow
s. By default, Qt apps will exit when that happens. You can disable this behavior by addingapp.setQuitOnLastWindowClosed(false);
inmain.cpp
-
@shaan7 said in Dynamic QML Page loader:
Wonderful!!! You deserve more than one like!!! Thank's a lot @shaan7 !!!