Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Switch between application modes during runtime



  • Hi,

    My application has two different operating modes, each of which makes use of different QML files and c++ classes. The selected/enabled operating mode is stored in a configuration file, which is loaded in main.cpp on startup of the application. At the moment, I'm only able to switch between operating modes by changing the selection in the configuration file and then restarting the application. I'd like to be able to switch operating modes during runtime, including destroying the previously initialised QML and c++ class objects, such that the newly selected operating mode functions as if it were selected on startup (i.e. no remaining allocated memory from the previous operating mode).

    The general layout of my main.cpp file is as follows:

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include "configuration.h"
    
    #include "path/to/operating/modeA.h"
    #include "other/modeA/header/files.h"
    
    #include "path/to/operating/modeB.h"
    #include "other/modeB/header/files.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        configuration *configurationClass = new configuration();
    
        configurationClass->setupConfiguration();
    
        QQmlApplication engine;
        
        //Determine which operating mode we're in
        if (configurationClass->operatingMode() == "modeA") {
        
            //modeA operation
            modeA *modeAOperatingClass = new modeA();
            engine.rootContext()->setContextProperty("modeA", modeAOperatingClass);
    
            engine.load(QUrl(QStringLiteral("qrc:/path/to/modeA/qmlFile/main.qml")));
    
        } else if (configurationClass->operatingMode() == "modeB") {
    
            //modeB operation
            modeB *modeBOperatingClass = new modeB();
            engine.rootContext()->setContextProperty("modeB", modeBOperatingClass);
      
            engine.load(QUrl(QStringLiteral("qrc:/path/to/modeB/qmlFile/main.qml")));
    
        }
    
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    Is there a standard/best practise way to:

    • Load the newly selected operating mode's qml file in the QQmlApplicationEngine
    • Instantiate the newly selected operating mode's class objects
    • Remove the previously selected operating mode's qml file from the QQmlApplicationEngine
    • Delete the previously selected operating mode's class objects


  • I gave this some further thought overnight. I think I should add a 'controller' class, which is initialised in main.cpp, which controls the launching of either modeA or modeB. This way I minimise the amount of logic/processing done in main.cpp and I can use signals/slots in the controller class (perhaps with a Loader in a corresponding 'controller' QML file to switch between the modeA and modeB QML files) to instantiate and delete modeA/modeB class objects as required.

    Does that make sense?


  • Lifetime Qt Champion

    Hi,

    You might also want to consider replacing your engine by a fresh new instance. It would give you a clean state to start from.



  • Ah, very good point. Would that 'delete old engine and initialise a new engine' process by done in main.cpp, or in a 'controller' class?


  • Moderators

    @jars121
    you can take a look at this project of mine:

    https://github.com/DeiVadder/RuntimeQmlReload

    It's my base setup for reloading QML components at runtime, so that I do not have to recompile the sources.

    You can of course simply replace the absolute file path to the 2nd file of your resources.

    At the very least, it should get you started!



  • @J-Hilk said in Switch between application modes during runtime:

    @jars121
    you can take a look at this project of mine:

    https://github.com/DeiVadder/RuntimeQmlReload

    It's my base setup for reloading QML components at runtime, so that I do not have to recompile the sources.

    You can of course simply replace the absolute file path to the 2nd file of your resources.

    At the very least, it should get you started!

    Thank you very much, that is indeed an excellent reference/starting point!

    I understand how you've used the Backend class within main.cpp and set it as a context property of the engine. If I wanted to instead call emit the Backend::reloadQML() signal from within a c++ class (not directly from a button/event in QML), is there a way of connecting to the Backend class from an external c++ class, or would Backend need to be external to main.cpp?


  • Moderators

    @jars121 said in Switch between application modes during runtime:

    Thank you very much, that is indeed an excellent reference/starting point!

    thank you ☺️

    I understand how you've used the Backend class within main.cpp and set it as a context property of the engine

    yes, alternatively you can also use a event filter on the QApplication that listens for the F5 key press. But as I learned, that only works if you do not listen to it on the QML form 🤷‍♂️

    If I wanted to instead call emit the Backend::reloadQML() signal from within a c++ class (not directly from a button/event in QML), is there a way of connecting to the Backend class from an external c++ class, or would Backend need to be external to main.cpp?

    You can simply forward signals, "until you reach main.cpp" where you then connect the signal to the function to reload the main component. You don't even need a Backend class, if you only want to emit it from c++.
    Anything works, as long as you can access the QQmlApplicationEngine, either by forwarding a pointer/reference to it or by forwarding signals to main



  • Thanks again @J-Hilk, you've certainly led me down the correct path.

    I've more or less got this process working now. I ended up using an external controller class, which is passed QPointers from main.cpp, to allow the controller class to instantiate, destroy and reinstantiate the operating mode classes as required, using the main.cpp objects.

    As far as this thread is concerned, I believe a solution has been reached, and I'll mark the thread as such. I'm still having issues with the QPointer process however, for which I'll start another thread as its not closely aligned with the objective of this thread.


Log in to reply