Reload a Loader on button click
-
wrote on 7 May 2019, 19:17 last edited by
Would creating dynamic QML objects work better than using a Loader?
https://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html -
wrote on 10 May 2019, 07:42 last edited by
Hi,
sorry for the late response, I had a lot of other stuff to do.
I tried with gc() and the hacky way, and a combination of both, and the result is the same as before.
I haven't try fcarney's solution yet, I will do it when I will have a some time, and tell you if it worked.Thanks
-
Here's how I do it,
maybe it's of help for your case://QuickWidget.h #ifndef QUICKWINDOW_H #define QUICKWINDOW_H #include <QQuickWindow> #include <QIcon> class QuickWindow : public QQuickWindow { Q_OBJECT public: explicit QuickWindow(QQuickWindow *parent = nullptr) : QQuickWindow(parent) {} signals: Q_INVOKABLE void reloadQML(); }; #endif // QUICKWINDOW_H
//main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include "quickwindow.h" void clearAndReload( QQmlApplicationEngine &engine){ for(QObject *obj : engine.rootObjects()){ engine.rootObjects().removeOne(obj); obj->deleteLater(); } engine.clearComponentCache(); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); for(QObject *obj : engine.rootObjects()){ QuickWindow *window = qobject_cast<QuickWindow*>(obj); if(window)QObject::connect(window, &QuickWindow::reloadQML, &engine,[&engine]{clearAndReload(engine);}); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); qmlRegisterType<QuickWindow>("QuickWindow", 1, 0, "QuickWindow"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; for(QObject *obj : engine.rootObjects()){ QuickWindow *window = qobject_cast<QuickWindow*>(obj); if(window) QObject::connect(window, &QuickWindow::reloadQML, &engine,[&engine]{clearAndReload(engine);}); } return app.exec(); }
//main.qml import QtQuick 2.12 import QtQuick.Controls 2.5 import QuickWindow 1.0 QuickWindow { id:root visible:true width:500; height:500 Component.onCompleted: console.log("Window created") Shortcut{ sequence: "F5" onActivated: { console.log("Reload") reloadQML() } } }
-
Here's how I do it,
maybe it's of help for your case://QuickWidget.h #ifndef QUICKWINDOW_H #define QUICKWINDOW_H #include <QQuickWindow> #include <QIcon> class QuickWindow : public QQuickWindow { Q_OBJECT public: explicit QuickWindow(QQuickWindow *parent = nullptr) : QQuickWindow(parent) {} signals: Q_INVOKABLE void reloadQML(); }; #endif // QUICKWINDOW_H
//main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include "quickwindow.h" void clearAndReload( QQmlApplicationEngine &engine){ for(QObject *obj : engine.rootObjects()){ engine.rootObjects().removeOne(obj); obj->deleteLater(); } engine.clearComponentCache(); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); for(QObject *obj : engine.rootObjects()){ QuickWindow *window = qobject_cast<QuickWindow*>(obj); if(window)QObject::connect(window, &QuickWindow::reloadQML, &engine,[&engine]{clearAndReload(engine);}); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); qmlRegisterType<QuickWindow>("QuickWindow", 1, 0, "QuickWindow"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; for(QObject *obj : engine.rootObjects()){ QuickWindow *window = qobject_cast<QuickWindow*>(obj); if(window) QObject::connect(window, &QuickWindow::reloadQML, &engine,[&engine]{clearAndReload(engine);}); } return app.exec(); }
//main.qml import QtQuick 2.12 import QtQuick.Controls 2.5 import QuickWindow 1.0 QuickWindow { id:root visible:true width:500; height:500 Component.onCompleted: console.log("Window created") Shortcut{ sequence: "F5" onActivated: { console.log("Reload") reloadQML() } } }
wrote on 14 May 2019, 12:34 last edited by@J.Hilk I cannot use any C++ code :( I'm using QML in an external software, I can't link both C++ and QML.
I tried to create / delete my objects dynamically like that :
main.qml
[...] StackLayout { [...] Loader{ id: loaderTestReload source: "tab1.qml" } [...] }
tab1.qml is use to create my object :
Item { id: tab1 property var compo Component.onCompleted: init() function init() { var component = Qt.createComponent("tab1_qml.qml") component.createObject(tab1) compo = component } function reload() { compo.destroy() init() } }
and then I have the main component, with 2 buttons and a text :
Item { id: tab1qml property int value: 0 Button{ id: button1 text: tab1qml.value onClicked: value++ } Button{ y: button1.height text: "reload" onClicked: tab1.reload() } Text{ y: button1.height*2 text: "reset ?" } }
When I press the reload button, the component is reloaded, but as before, my app keeps the file in memory. If I change my text, it will remain as it was.
I will take a look at the example, it uses createQmlObject() instead of createComponent(). Maybe I can store the content of the file and send it via createQmlObject(). -
@J.Hilk I cannot use any C++ code :( I'm using QML in an external software, I can't link both C++ and QML.
I tried to create / delete my objects dynamically like that :
main.qml
[...] StackLayout { [...] Loader{ id: loaderTestReload source: "tab1.qml" } [...] }
tab1.qml is use to create my object :
Item { id: tab1 property var compo Component.onCompleted: init() function init() { var component = Qt.createComponent("tab1_qml.qml") component.createObject(tab1) compo = component } function reload() { compo.destroy() init() } }
and then I have the main component, with 2 buttons and a text :
Item { id: tab1qml property int value: 0 Button{ id: button1 text: tab1qml.value onClicked: value++ } Button{ y: button1.height text: "reload" onClicked: tab1.reload() } Text{ y: button1.height*2 text: "reset ?" } }
When I press the reload button, the component is reloaded, but as before, my app keeps the file in memory. If I change my text, it will remain as it was.
I will take a look at the example, it uses createQmlObject() instead of createComponent(). Maybe I can store the content of the file and send it via createQmlObject().Indulge me for a bit, as I have not done this before. How do you start a QML application without a main- function?
-
Indulge me for a bit, as I have not done this before. How do you start a QML application without a main- function?
wrote on 14 May 2019, 13:04 last edited by Dylan_Alt.@J.Hilk I don't how it's made behind. The software uses blocks to code (like Unreal Engine for example, but at a much higher level than simple instructions). One of these blocks is a QML Viewer, where I can set a main.qml file, up to 32 input property and as many outputs as I want. I don't have any control of what happens when the full application is started.
-
@J.Hilk I don't how it's made behind. The software uses blocks to code (like Unreal Engine for example, but at a much higher level than simple instructions). One of these blocks is a QML Viewer, where I can set a main.qml file, up to 32 input property and as many outputs as I want. I don't have any control of what happens when the full application is started.
@Dylan_Alt.
alight,that's unfortunate, as it limits your options quite heavily.
-
wrote on 24 May 2019, 06:50 last edited by
I took my time to test several things and I found something that worked :
I used createQmlObject(), to load the content of the file, instead of createComponent(). Here is how it looks like :Tab1.qml :
Item { id: tab1 property var compo Component.onCompleted: init() function init() { var xhr = new XMLHttpRequest; var response xhr.open("GET", "tab1_qml.qml"); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { response = xhr.responseText; compo = Qt.createQmlObject(response, tab1,"tab1_qml.qml") } }; xhr.send(); // begin the request } function reload() { compo.destroy() init() } }
tab1_qml.qml :
Item { id: tab1qml property int value: 0 Button{ id: button1 text: tab1qml.value onClicked: value++ } Button{ y: button1.height text: "reload" onClicked: tab1.reload() } Text{ y: button1.height*2 text: "reset ?" } }
When I modify my tab1_qml.qml and clic the reload button, it works.
But bad news, it works well on my software, but it doesn't work on QtCreator. As far as I understand, it's because the file is loaded from the ressource, the solution may be to take an external qml file.
Anyway, my problem is solved.Thanks everyone who responsed.
-
I took my time to test several things and I found something that worked :
I used createQmlObject(), to load the content of the file, instead of createComponent(). Here is how it looks like :Tab1.qml :
Item { id: tab1 property var compo Component.onCompleted: init() function init() { var xhr = new XMLHttpRequest; var response xhr.open("GET", "tab1_qml.qml"); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { response = xhr.responseText; compo = Qt.createQmlObject(response, tab1,"tab1_qml.qml") } }; xhr.send(); // begin the request } function reload() { compo.destroy() init() } }
tab1_qml.qml :
Item { id: tab1qml property int value: 0 Button{ id: button1 text: tab1qml.value onClicked: value++ } Button{ y: button1.height text: "reload" onClicked: tab1.reload() } Text{ y: button1.height*2 text: "reset ?" } }
When I modify my tab1_qml.qml and clic the reload button, it works.
But bad news, it works well on my software, but it doesn't work on QtCreator. As far as I understand, it's because the file is loaded from the ressource, the solution may be to take an external qml file.
Anyway, my problem is solved.Thanks everyone who responsed.
wrote on 13 Jul 2020, 19:44 last edited by@Dylan_Alt I realize this is a pretty old thread and this is a pretty hacky response, but it appears to work for both local and remote files.
onClicked { myLoader.source = "MyLocalOrRemoteFile.qml?"+Math.random() }
-
@Dylan_Alt I realize this is a pretty old thread and this is a pretty hacky response, but it appears to work for both local and remote files.
onClicked { myLoader.source = "MyLocalOrRemoteFile.qml?"+Math.random() }