Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Reload a Loader on button click

Reload a Loader on button click

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlloader
16 Posts 6 Posters 10.9k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Dylan_Alt.
    7 May 2019, 11:48

    Thanks for your response !

    Both of your solution work, but it seems that the application keeps the initial qml file in memory. If I change my code live and reload it, my app will still load the file without the new modification.

    J Offline
    J Offline
    J.Hilk
    Moderators
    wrote on 7 May 2019, 12:19 last edited by
    #5

    @Dylan_Alt. that's because the component cache is not cleared.

    But I don't know how to force this from QML side. Maybe forcing the garbage collector to run in-between ? gc()

    usually you would call clearComponentCache on your QQmlApplicationEngine inside you main.cpp for that.

    Or that's where I do it ;)


    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


    Q: What's that?
    A: It's blue light.
    Q: What does it do?
    A: It turns blue.

    1 Reply Last reply
    3
    • S Offline
      S Offline
      sierdzio
      Moderators
      wrote on 7 May 2019, 19:03 last edited by
      #6

      Note that the cached properties will be cleared if the source or sourceComponent is changed after calling this function but prior to setting the loader active.

      That's from https://doc.qt.io/qt-5/qml-qtquick-loader.html. So the solution might be to get the right combination of active: false, then set source, then 'active: true`, but it sounds very hacky. What @J-Hilk proposed seems better.

      (Z(:^

      1 Reply Last reply
      2
      • F Offline
        F Offline
        fcarney
        wrote on 7 May 2019, 19:17 last edited by
        #7

        Would creating dynamic QML objects work better than using a Loader?
        https://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        0
        • D Offline
          D Offline
          Dylan_Alt.
          wrote on 10 May 2019, 07:42 last edited by
          #8

          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

          1 Reply Last reply
          0
          • J Offline
            J Offline
            J.Hilk
            Moderators
            wrote on 10 May 2019, 07:54 last edited by
            #9

            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()
                    }
                }
            }
            
            

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            D 1 Reply Last reply 14 May 2019, 12:34
            0
            • J J.Hilk
              10 May 2019, 07:54

              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()
                      }
                  }
              }
              
              
              D Offline
              D Offline
              Dylan_Alt.
              wrote on 14 May 2019, 12:34 last edited by
              #10

              @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 1 Reply Last reply 14 May 2019, 12:42
              0
              • D Dylan_Alt.
                14 May 2019, 12:34

                @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 Offline
                J Offline
                J.Hilk
                Moderators
                wrote on 14 May 2019, 12:42 last edited by
                #11

                @Dylan_Alt.

                Indulge me for a bit, as I have not done this before. How do you start a QML application without a main- function?


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                D 1 Reply Last reply 14 May 2019, 13:04
                0
                • J J.Hilk
                  14 May 2019, 12:42

                  @Dylan_Alt.

                  Indulge me for a bit, as I have not done this before. How do you start a QML application without a main- function?

                  D Offline
                  D Offline
                  Dylan_Alt.
                  wrote on 14 May 2019, 13:04 last edited by Dylan_Alt.
                  #12

                  @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 1 Reply Last reply 14 May 2019, 13:13
                  1
                  • D Dylan_Alt.
                    14 May 2019, 13:04

                    @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 Offline
                    J Offline
                    J.Hilk
                    Moderators
                    wrote on 14 May 2019, 13:13 last edited by
                    #13

                    @Dylan_Alt.
                    alight,

                    that's unfortunate, as it limits your options quite heavily.


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      Dylan_Alt.
                      wrote on 24 May 2019, 06:50 last edited by
                      #14

                      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.

                      9 1 Reply Last reply 13 Jul 2020, 19:44
                      1
                      • D Dylan_Alt.
                        24 May 2019, 06:50

                        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.

                        9 Offline
                        9 Offline
                        99hats
                        wrote on 13 Jul 2020, 19:44 last edited by
                        #15

                        @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()
                        }
                        
                        _ 1 Reply Last reply 19 May 2023, 11:48
                        2
                        • 9 99hats
                          13 Jul 2020, 19:44

                          @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()
                          }
                          
                          _ Offline
                          _ Offline
                          _nezticle
                          wrote on 19 May 2023, 11:48 last edited by
                          #16

                          @99hats lol, that is a good solution and I can confirm that it does work. (though since it's being cheeky, it likely just fills up the component cache)

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved