使用ApplicationWindow时如何进行QML热重载

7
有人能够在使用ApplicationWindow时热重载所有QML文件吗?我找到了一些例子,例如https://qml.guide/live-reloading-hot-reloading-qml/https://www.slideshare.net/ICSinc/how-best-to-realize-a-runtime-reload-of-qml,但大多数都使用Loader,因为ApplicationWindow需要是根元素,所以这样不起作用(没有窗口出现),无法重新加载所有QML内容。
我尝试过:
ApplicationWindow {
    id: window
    visibility: "FullScreen"

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

这里的 app 是我在 C++ 代码中设置的上下文属性,该函数执行的操作是:

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")));
}

这段代码有时能够正常运行,窗口会消失然后出现,但是快捷键只能用一次,第二次就不起作用了... 有什么想法可以实现这个功能吗?

你能分享一个完整的最小示例吗?这样更容易找出问题所在。我很惊讶第一次就能工作,因为你关闭了“Shortcut”的父级。 - bardao
1个回答

7
这是我所做的,并且它正常运行: 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()
        }
    }
}

你也可以将“Window”替换为“ApplicationWindow”,这样每次启动都能正常工作。 - bardao
只需删除context: Qt.ApplicationShortcut - bardao
感谢您的回答@bardao。删除context: Qt.ApplicationShortcut确实有所改善。我的应用现在在退出时崩溃了,但至少热重载似乎是有效的。细节:在我的情况下,appQGuiApplication的子类,因此没有像您代码中的apppapp。感谢您的帮助! - marsl
@marsl 在一个最小的示例中重现问题可能会非常有帮助 :) - bardao
据我理解,这个解决方案并没有卸载/删除旧窗口。它仍然留在引擎中。对我来说,这会导致一些问题(我有一个复杂的设置,自己的OpenGL绘图,大型对象等)。是的,也许可以解决。然而,关闭和重新打开窗口也很烦人:它不保持其几何形状,并且窗口状态被清除(例如Z索引)。这是一个概念性的问题。因此,我将坚持仅重新加载内容,这是https://github.com/KDAB/kdabtv/blob/master/Qt-Embedded-Cycletime/video2_hot_reload/ledApp/main.qml中显示的解决方案(带有一些适应性)。 - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接