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
QtWS25 Last Chance

Reload a Loader on button click

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlloader
16 Posts 6 Posters 10.8k 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 Offline
    D Offline
    Dylan_Alt.
    wrote on 7 May 2019, 09:17 last edited by
    #1

    Hi,

    I have a problem to reload some Loader in my application.
    I have a StackLayout with all my loaders :

    StackLayout {
    	id: mainLayout
    		
    	y: backgroundTab.height
    		
            currentIndex: 0
    
            Loader{
    	    id: loaderApplication
                source: "Application/Application.qml"
            }
            Loader{
    	    id: loaderRecord
                source: "Record/Record.qml"
            }
            [...]
        }
    

    Within my loaders, I have 2 buttons : the first one is a counter (that should be reset after the reload), and the second the reload button.

    The thing is I'm using QML within RTMaps (an external software), so I'm very limited : I can't use C++ in addition to QML.
    Solutions I found all use C++, so I'm a little bit lost.

    If someone has some clues, that will be helpfull !

    Thanks

    1 Reply Last reply
    0
    • S Offline
      S Offline
      sierdzio
      Moderators
      wrote on 7 May 2019, 10:02 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 1 Reply Last reply 7 May 2019, 11:07
      4
      • S sierdzio
        7 May 2019, 10:02

        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 Offline
        J Offline
        J.Hilk
        Moderators
        wrote on 7 May 2019, 11:07 last edited by J.Hilk 5 Jul 2019, 11:15
        #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
        • D Offline
          D Offline
          Dylan_Alt.
          wrote on 7 May 2019, 11:48 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 1 Reply Last reply 7 May 2019, 12:19
          0
          • 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
              • fcarneyF Offline
                fcarneyF 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