7

Has anyone been able to hot reload all QML files when using a ApplicationWindow? I found a few examples like https://qml.guide/live-reloading-hot-reloading-qml/ and https://www.slideshare.net/ICSinc/how-best-to-realize-a-runtime-reload-of-qml, but mostly they use Loader and as ApplicationWindow needs to be the root item, this does not work (no window appears) to just reload all QML stuff.

I tried:

ApplicationWindow {
    id: window
    visibility: "FullScreen"

    Shortcut {
        sequence: "F5"
        context: Qt.ApplicationShortcut
        onActivated: {
            window.close();
            app.loadQml();
        }
    }
    ...
}

where app is a context property I set on C++ side and the function does:

void App::loadQml()
{
    qml_engine_.clearComponentCache();
    // Use "qrc:/Main.qml" for Qt Resource System.
    // Use "Main.qml" for file system.
    qml_engine_.load(QUrl(QStringLiteral("Main.qml")));
}

This code kind of works once, the window dis- and reapears but the shortcut only works once but no second time...

Any ideas how to implement this?

marsl
  • 959
  • 1
  • 14
  • 25
  • Can you share a complete minimal example? it'll be easier to figure out the issue. I'm surprised it's working the first time, you're closing the parent of `Shortcut` – bardao Mar 13 '19 at 20:20

1 Answers1

7

Here's what I did and it's working fine: main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "app.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    QQmlApplicationEngine engine;

    App appp;
    appp.setEngine(&engine);

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

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

app.cpp:

#include "app.h"

App::App(QObject *parent): QObject (parent)
{

}

App::~App(){}

void App::loadQml()
{
    m_engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
}

app.h:

#ifndef APP_H
#define APP_H
#include <QObject>
#include <QQmlApplicationEngine>

class App: public QObject
{

    Q_OBJECT
public:
    App(QObject* parent = Q_NULLPTR);
    ~App();

    Q_INVOKABLE void loadQml();
    void setEngine(QQmlApplicationEngine *engine) { m_engine = engine; }

private:
    QQmlApplicationEngine* m_engine;
};

#endif // APP_H

main.qml:

import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import QtQuick.Window 2.11

Window {
    id: window
    width: 1000
    height: 1000
    visible: true

    Shortcut {
        sequence: "F5"
        onActivated: {
            window.close()
            app.loadQml()
        }
    }
}
bardao
  • 914
  • 12
  • 23
  • you can also replace `Window` with `ApplicationWindow`, still works on every launch – bardao Mar 13 '19 at 22:43
  • just remove `context: Qt.ApplicationShortcut` – bardao Mar 13 '19 at 22:46
  • Thanks for you answer @bardao. Removing `context: Qt.ApplicationShortcut` really improved it. My application is crashing on exit now, but at least the hot reload seems to work. Detail: In may case, `app` is a subclass of `QGuiApplication`, so there's no `appp` and `app` as in your code. Thanks for your help! – marsl Mar 14 '19 at 06:56
  • @marsl reproducing the issue in a minimal example can be extremely helpful :) – bardao Mar 14 '19 at 18:09
  • to my understanding, this solution doesn't unload/delete the old window. it stays in the engine. for me this causes a problems (i have a complex setup with my own opengl drawing, largish objects etc). yes maybe solvable. however, it's also annoying that the window is closed and reopened: it doesn't keep its geometry, and the window state is killed (e.g. z index). That's something conceptual. So i'll stick to reloading the content only, that is the solution shown in https://github.com/KDAB/kdabtv/blob/master/Qt-Embedded-Cycletime/video2_hot_reload/ledApp/main.qml (with some adaptations). – Adam Jun 01 '23 at 11:18