Force Loader reload



  • I have a Quick Controls 2 app and I need to expose the QQmlEngine inside it.

    Maybe something like this:

    MyEngine {
    id: myEngine
    }

    and then I can call myEngine.clear()

    The clear() function is in a C++ class called MyEngine, like this

    void MyEngine::clear()
    {
    myCurrentQmlEngine->clearComponentCache();
    }

    However, I can't find out how to make myCurrentQmlEngine reference the current QML Engine (QQmlEngine). I imagine that needs to happen in MyEngine's constructor.

    Anyone know how to do this?

    (Or does anyone know a better way of forcing a Loader to reload without pulling from the qml engine's cache?)



  • @JeTSpice You don't need an instantiable type nor do you need to instantiate a type in QML. Use setContextProperty with a QObject based object which has a slot or a Q_INVOKABLE method which calls clearComponentCache(). You can even subclass QQmlApplicationEngine, create an object out of it in C++ and set itself as its own context property and use it to load and run QML. Then use it as a global object in QML.

    class MyEngine : public QQmlApplicationEngine
    {
        Q_OBJECT
    public:
        Q_INVOKABLE void clear() { clearComponentCache(); }
    ...
    
    //main.cpp
        MyEngine engine;
        engine.rootContext()->setContextProperty("myEngine", &engine);
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
    // qml javascript
    myEngine.clear()
    


  • Thank you for your help.
    I'm getting a compile error:

    invalid use of incomplete type 'class QQmlContext'

    at this line:

    engine.rootContext()->setContextProperty("myEngine", &engine);

    It looks like that means rootContext does not yet exist at that moment?

    Here is my main.cpp file:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    class MyEngine : public QQmlApplicationEngine
    {
        Q_OBJECT
    public:
        Q_INVOKABLE void clear() { clearComponentCache(); }
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        MyEngine engine;
        engine.rootContext()->setContextProperty("myEngine", &engine);
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    


  • @JeTSpice That's a normal situation in C++ - you just have to add a header:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext> //this!
    
    class MyEngine : public QQmlApplicationEngine
    {
    

    It's also possible that you have to move MyEngine in its own file or add some macro directive (I don't remember which one) in main.cpp. Otherwise Qt's moc preprocessor can't create the needed metaclass.



  • It works now.
    I had to recreate MyEngine as an external file (.h file and .cpp file)

    A co-worker found out that MyEngine needs to delay clearing the cache or it will conflict with rendering (painting, i think its called in qml). A delay interval of 0 (zero) works.

    As far as forcing the Loader to reload, we found that the source url needs to be absolute, for instance:

    "File:///Users/JohnDoe/Documents/RedRectangle.qml"
    

    The source url can point to a file in a qml project.
    In our case, we don't set the Loader.source to an empty string and then re-set it back. Simply calling myengine.clear() works.

    Solved. Thanks for your help.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.