【问题标题】:QML Loader not shows changes on .qml fileQML Loader 不显示 .qml 文件的更改
【发布时间】:2013-11-05 10:33:43
【问题描述】:

我有main.qmldynamic.qml 文件,我想使用Loader {}main.qml 上加载dynamic.qml
dynamic.qml 文件的内容是动态的,其他程序可能会更改其内容并覆盖它。 所以我写了一些 C++ 代码来检测文件的变化并触发 Signal。
我的问题是我不知道如何强制 Loader 重新加载文件。

这是我目前的工作:

MainController {
    id: mainController
    onInstallationHelpChanged: {
        helpLoader.source = "";
        helpLoader.source = "../dynamic.qml";
    }
}

Loader {
    id: helpLoader

    anchors.fill: parent
    anchors.margins: 60
    source: "../dynamic.qml"
}



我认为 QML 引擎缓存 dynamic.qml 文件。因此,每当我想重新加载 Loader 时,它都会显示旧内容。有什么建议吗?

【问题讨论】:

    标签: caching qml qt5 dynamic-data


    【解决方案1】:

    您需要在 QQmlEngine 上调用trimComponentCache()您已将 Loaders source 属性设置为空字符串。换句话说:

    helpLoader.source = "";
    // call trimComponentCache() here!!!
    helpLoader.source = "../dynamic.qml";
    

    为了做到这一点,您需要向 QML 公开一些 C++ 对象,该对象引用您的 QQmlEngine(Qt 和 StackOverflow 中的大量示例可以帮助解决此问题)。

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

    【讨论】:

    • 谢谢,但我该怎么做呢?
    • 我添加了更多细节。我希望你能从那里拿走它。
    • 我唯一要做的就是使用QPointer 代替QQmlEngine。一般来说,除非您在给定的上下文中拥有QObject,否则您不应该使用指向它的裸指针。
    • @KubaOber 当然,这是一个公平的观点。但是,在这种情况下,QML 应用程序通常会在执行开始时创建一个 QQmlEngine 并在关闭时将其销毁,因此取消引用空指针的风险非常小。但这仍然是一个好点。
    • 谢谢。我通过使用qmlRegisterSingletonType 创建一个 Qml 类型来实现您的建议。但是trimComponentCache() 不起作用。相反clearComponentCache() 有效。谢谢你!
    【解决方案2】:

    我希望有一个纯 QML 解决方案。我注意到 loader.source 是一个 url (file:///) 并记得使用 HTML,您可以在请求中使用 ?t=Date.now() 避免 HTTP 缓存。试过在loader.source后面加?t=1234,果然成功了。

    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()
            }
        }
    
    }
    

    【讨论】:

    • 这对 Windows 下的 Qt 5.9.1 32Bit 不起作用,它接受带有附加时间戳的新文件名,但 qml 中的更改不显示。
    猜你喜欢
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多