Правильная перезагрузка QQmlApplicationEngine

У меня есть приложение на основе QML, которое загружает main.qml файл из файловой системы примерно так:

myEngine->load("main.qml");

Это прекрасно работает, но я бы хотел "перезагрузить" движок, если файл main.qml был заменен более новой версией.

То, что я пытался до сих пор, называлось load() снова, предполагая, что движок автоматически перезагрузится, как в других классах Qt.

К сожалению, это не случай. Если я вызову метод еще раз, появится другое окно с содержимым обновленного файла qml, а исходное окно останется открытым и продолжит отображать старый файл qml.

Чтобы это исправить я попытался позвонить load(QUrl()), с последующим clearComponentCache() и последний вызов загрузки для нового файла. Это приводит к тому же эффекту.

Любые идеи, как я могу "правильно" перезагрузить движок QML во время работы приложения?

3 ответа

Решение

Я бы попробовал хранить myEngine в качестве указателя на кучу и удаления его после вызова quit (). Затем вы можете восстановить его, чтобы получить новую версию файла QML.

Если вы не хотите делать это по какой-либо причине (например, из-за того, что хотите сохранить окно или что-то в этом роде), вы можете попробовать использовать Loader и загрузка файла QML таким образом. Ваш main.qml будет выглядеть примерно так:

import QtQuick 2.0

Loader {
     source: "changing.qml"
}

Всякий раз, когда вы обнаружите, что changing.qml изменилось, просто переключите активное свойство Loader запустить перезагрузку файла.

Просто видел это, но если вы все еще пытаетесь понять это - это трехэтапный процесс, и у вас есть кое-что из этого.

  1. Вы ДОЛЖНЫ закрыть окно, созданное QQmlApplicationEngine первый. В моем случае я вытащил первый корневой объект с QQmlApplicationEngine и бросить его QQuickWindowзатем позвоните close(),

  2. Теперь вы можете позвонить clearComponentCache на QQmlApplicationEngine,

Это то, что делает мой код закрытия окна (обратите внимание, что я дал моему главному окну objectName)

QObject* pRootObject = in_pQmlApplicationEngine->rootObjects().first();
Q_ASSERT( pRootObject != NULL );
Q_ASSERT( pRootObject->objectName() == "mainWindow" );

QQuickWindow* pMainWindow = qobject_cast<QQuickWindow*>(pRootObject);
Q_ASSERT( pMainWindow );
pMainWindow->close();

Третий шаг, конечно, загрузить ваш QML.

Позже я перешел к созданию QQuickView окно вместо QQmlApplicationEngineчтобы я мог просто позвонить clearComponentCache а потом setSource (Мне не понравилось, что пользователь видит, как окно пользовательского интерфейса исчезает, а затем снова появляется.)

Использование файлового наблюдателя:

main.py

      DEBUG = True


class EntryPoint(qtc.QObject):
    if DEBUG:
        qmlFileChanged = qtc.Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.qml_engine = qqml.QQmlApplicationEngine()
        self.qml_entry = str(PATHS.playground.resolve())
        self.qml_engine.load(self.qml_entry)
        if DEBUG:
            qml_files = []
            for file in glob.iglob('**/*.qml', root_dir=PATHS.QML, recursive=True):
                qml_files.append(str((PATHS.QML / file).resolve()))
            self.file_watcher = QFileSystemWatcher(self)
            self.file_watcher.addPaths(qml_files)
            self.file_watcher.fileChanged.connect(self.on_qml_file_changed)

    if DEBUG:
        @slot
        def on_qml_file_changed(self) -> None:  # pragma: no cover
            self.qml_engine.clearComponentCache()
            window: QQuickItem = self.qml_engine.rootObjects()[0]
            loader: QQuickItem = window.findChild(QQuickItem, 'debug_loader')
            qtc.QEventLoop().processEvents(qtc.QEventLoop.ProcessEventsFlag.AllEvents, 1000)
            prev = loader.property("source")
            loader.setProperty('source', "")
            loader.setProperty('source', prev)

площадка.qml

      import QtQuick
import QtQuick.Controls.Material

Window {
    id: root
    width: 1200
    height: 900
    visible: true
    flags: Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint | Qt.CustomizeWindowHint | Qt.WindowTitleHint
    Material.theme: Material.Dark
    Material.accent: Material.Cyan

    Pane {
        anchors.fill: parent
        objectName: "_rootRect"
        Loader{id: loader
            objectName: "debug_loader"
            anchors.fill: parent;
            source:"anything.qml"
        }
    }

}

Другие вопросы по тегам