QML Loader не показывает изменения в файле.qml
Я имею main.qml
а также dynamic.qml
файлы, которые я хочу загрузить dynamic.qml
на main.qml
с помощью Loader {}
,
Содержание dynamic.qml
Файл является динамическим, и другая программа может изменить его содержимое и перезаписать его. Поэтому я написал код на C++ для обнаружения изменений в файле и запуска сигнала.
Моя проблема в том, что я не знаю, как заставить загрузчик перезагрузить файл.
Это моя текущая работа:
MainController {
id: mainController
onInstallationHelpChanged: {
helpLoader.source = "";
helpLoader.source = "../dynamic.qml";
}
}
Loader {
id: helpLoader
anchors.fill: parent
anchors.margins: 60
source: "../dynamic.qml"
}
Я думаю, что QML Engine кеширует dynamic.qml
файл. Поэтому всякий раз, когда я хочу перезагрузить Loader, он показывает старый контент. Любое предложение?
2 ответа
Вам нужно позвонить trimComponentCache()
на QQmlEngine после того, как вы установили Loaders source
свойство пустой строки. Другими словами:
helpLoader.source = "";
// call trimComponentCache() here!!!
helpLoader.source = "../dynamic.qml";
Чтобы сделать это, вам нужно представить некоторый объект C++ для QML, который имеет ссылку на ваш QQmlEngine (множество примеров в Qt и в Stackru помогут в этом).
trimComponentCache говорит QML забыть обо всех компонентах, которые не используются в данный момент, и выполняет только то, что вы хотите.
Обновление - объясняя немного подробнее:
Например, где-то вы определяете класс, который берет указатель на ваш QQmlEngine и предоставляет метод trimComponentCache:
class ComponentCacheManager : public QObject {
Q_OBJECT
public:
ComponentCacheManager(QQmlEngine *engine) : engine(engine) { }
Q_INVOKABLE void trim() { engine->trimComponentCache(); }
private:
QQmlEngine *engine;
};
Затем, когда вы создаете свой QQuickView, свяжите одно из вышеперечисленного как свойство контекста:
QQuickView *view = new QQuickView(...);
...
view->rootContext()->setContextProperty(QStringLiteral("componentCache", new ComponentCacheManager(view->engine());
Тогда в вашем QML вы можете сделать что-то вроде:
helpLoader.source = "";
componentCache.trim();
helpLoader.source = "../dynamic.qml";
Я надеялся на чистое решение QML. Я заметил, что loader.source
это URL (file:///
) и вспомнил, как с помощью HTML вы можете избежать HTTP-кэширования, используя ?t=Date.now()
в ваших запросах. Пробовал добавлять ?t=1234
до конца loader.source
и, конечно же, это работает.
import QtQuick 2.0
Item {
Loader {
id: loader
anchors.fill: parent
property string filename: "User.qml"
source: filename
function reload() {
source = filename + "?t=" + Date.now()
}
}
Timer {
id: reloadTimer
interval: 2000
repeat: true
running: true
onTriggered: {
loader.reload();
}
}
}
Я также написал другой пример, который проверит изменения содержимого файла, прежде чем запускать перезагрузку с использованием XMLHttpRequest.
import QtQuick 2.0
Item {
Loader {
id: loader
anchors.fill: parent
property string filename: "AppletUser.qml"
property string fileContents: ""
source: ""
function reload() {
source = filename + "?t=" + Date.now()
}
function checkForChange() {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState === 4) {
if (loader.fileContents != req.responseText) {
loader.fileContents = req.responseText;
loader.reload();
}
}
}
req.open("GET", loader.filename, true);
req.send();
}
onLoaded: {
console.log(source)
}
Timer {
id: reloadTimer
interval: 2000
repeat: true
running: true
onTriggered: loader.checkForChange()
}
Component.onCompleted: {
loader.checkForChange()
}
}
}