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.
  • sierdzioS Offline
    sierdzioS Offline
    sierdzio
    Moderators
    wrote on last edited by
    #2

    Simplest way to reload a loader:

    // In some JS function, like button click handler:
    loaderRecord.source = ""
    loaderRecord.source = "Record/Record.qml"
    

    But I suspect you are asking about something else, right?

    (Z(:^

    J.HilkJ 1 Reply Last reply
    4
    • sierdzioS sierdzio

      Simplest way to reload a loader:

      // In some JS function, like button click handler:
      loaderRecord.source = ""
      loaderRecord.source = "Record/Record.qml"
      

      But I suspect you are asking about something else, right?

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by J.Hilk
      #3

      @sierdzio I haven't tested it, but shouldn't this be the same, as setting the active property to false, and to true again ?


      Edit:
      jup made a small test:

      ApplicationWindow {
          id:root
          visible:true
          width:500; height:500
      
          Button {
              id:btn
              anchors.top: parent.top
              anchors.left: parent.left
              anchors.right: parent.right
              height:  50
      
              onClicked: {
                  load.active = !load.active
      
                  load.active = !load.active
              }
          }
      
          Loader{
              id:load
              anchors.left: parent.left
              anchors.right: parent.right
              anchors.bottom: parent.bottom
              anchors.top: btn.bottom
      
              source: "TestFile.qml"
          }
      }
      
      //TestFile.qml
      import QtQuick 2.0
      
      Rectangle {
          color: "blue"
      
          Component.onCompleted: console.log("completed")
          Component.onDestruction: console.log("Destructed")
      
      }
      

      works fine enough, completed and destructed is printed each time


      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
      1
      • Dylan_Alt.D Offline
        Dylan_Alt.D Offline
        Dylan_Alt.
        wrote on last edited by
        #4

        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.HilkJ 1 Reply Last reply
        0
        • Dylan_Alt.D Dylan_Alt.

          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.HilkJ Offline
          J.HilkJ Offline
          J.Hilk
          Moderators
          wrote on 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
          • sierdzioS Offline
            sierdzioS Offline
            sierdzio
            Moderators
            wrote on 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
            • fcarneyF Offline
              fcarneyF Offline
              fcarney
              wrote on 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
              • Dylan_Alt.D Offline
                Dylan_Alt.D Offline
                Dylan_Alt.
                wrote on 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.HilkJ Offline
                  J.HilkJ Offline
                  J.Hilk
                  Moderators
                  wrote on 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.

                  Dylan_Alt.D 1 Reply Last reply
                  0
                  • J.HilkJ J.Hilk

                    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()
                            }
                        }
                    }
                    
                    
                    Dylan_Alt.D Offline
                    Dylan_Alt.D Offline
                    Dylan_Alt.
                    wrote on 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.HilkJ 1 Reply Last reply
                    0
                    • Dylan_Alt.D Dylan_Alt.

                      @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.HilkJ Offline
                      J.HilkJ Offline
                      J.Hilk
                      Moderators
                      wrote on 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.

                      Dylan_Alt.D 1 Reply Last reply
                      0
                      • J.HilkJ J.Hilk

                        @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?

                        Dylan_Alt.D Offline
                        Dylan_Alt.D Offline
                        Dylan_Alt.
                        wrote on 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.HilkJ 1 Reply Last reply
                        1
                        • Dylan_Alt.D 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.HilkJ Offline
                          J.HilkJ Offline
                          J.Hilk
                          Moderators
                          wrote on 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
                          • Dylan_Alt.D Offline
                            Dylan_Alt.D Offline
                            Dylan_Alt.
                            wrote on 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
                            1
                            • Dylan_Alt.D Dylan_Alt.

                              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 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
                              2
                              • 9 99hats

                                @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 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