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
Forum Updated to NodeBB v4.3 + New Features

Reload a Loader on button click

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlloader
16 Posts 6 Posters 11.1k Views 1 Watching
  • 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.
  • 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