是否可以卸载通过QQmlApplicationEngine::load() 加载的QML对象?

编程语言 2026-07-12

我有一个C++类,它暴露了一个属性,并且有一个使用它的QML接口。下面是一个可工作的示例(test.cpp):

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>  
#include <QtQuick/QQuickItem>

class Exposed : public QQuickItem {
        Q_OBJECT
    public:
        Q_PROPERTY(int property READ getProperty NOTIFY never)
        ~Exposed() { qInfo() << "I'm done for"; }
        int getProperty() {
            qInfo() << "What's the meaning of all this?..";
            return 42;
        }
    signals:
        void never();
};

int main(int argc, char* argv[]) {
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    Exposed e;
    engine.rootContext()->setContextProperty("exposed", &e);
    engine.load("test.qml");
    return app.exec();
}

#include "test.moc"

以及QML(test.qml):

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    visible: true
    Text { text: exposed.property }
}

程序输出如下:

What's the meaning of all this?..
I'm done for
file:///home/user/work/test-qt/test.qml:6: TypeError: Cannot read property 'property' of null

错误信息之所以出现,是因为 eengine 之前被删除。通过交换对象定义的顺序,我可以避免这个问题:

    ...
    Exposed e;
    QQmlApplicationEngine engine;
    ...

现在引擎在暴露对象之前被销毁,一切正常。

但如果我无法控制对象的创建/销毁顺序(代码不是我写的)呢?有没有办法手动卸载用 QQmlApplicationEngine::load() 加载的QML接口?大致像这样:

    QQmlApplicationEngine engine;
    Exposed e;
    engine.rootContext()->setContextProperty("exposed", &e);
    engine.load("test.qml");
    app.exec();
    engine.unload_the_object_loaded_two_lines_above();
    // e will still be destroyed before engine but that's fine because nobody needs it anymore

请不要对这个问题过于字面地理解,如果你认为整件事应该以不同的方式完成,或者对该主题有其他看法,欢迎提出。

解决方案

没有直接的卸载方式,但你可以通过销毁根对象来达到同样的效果。

for (QObject* obj : engine.rootObjects())
    delete obj;

或者你可以将Loader作为根元素,并将其source设为空字符串,这样其子项就会被“卸载”。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章