JavaScript 在 QML 中动态创建与销毁对象详解

作者:闭包旅人时间:2026-10-24 20:58:54浏览:346

本文介绍如何在 QML 中使用 JavaScript 动态创建和销毁对象。主要涵盖通过 [[wp:a0]] 和 [[wp:a1]] 两种动态创建方式,以及利用 [[wp:a12]] 方法安全移除实例。文章详细解析了参数语义、静态构建注意事项及性能优化建议,帮助开发者掌握 QML 对象生命周期管理。

一、动态创建对象

在 QML 中,可以通过 JavaScript 实现对象的动态生成,主要包含以下两种途径:

  • 调用 Qt.createComponent() 动态创建 Component 对象
  • 使用 Qt.createQmlObject() 从 QML 字符串创建对象

需要注意的是,通过动态方式创建的对象虽然可以像常规对象一样使用,但它们不会在 QML 系统中分配 id。

1.1、动态创建组件

可以通过调用组件的 createObject() 方法来生成该组件的一个具体实例。该方法支持接收两个参数:

第一个参数用于指定新对象的父对象。父对象可以是图形元素(继承自 Item 类型)或非图形元素(如 QtObject 或 C++ QObject 类型)。只有拥有图形父对象的图形对象才会被渲染到 Qt Quick 可视画布上。若计划稍后设置父级关系,可以向此函数传递 null。第二个参数是可选的属性值映射表,用于定义对象的初始属性。在对象创建完成前应用这些属性值,能有效避免因特定属性未初始化而引发的绑定错误。此外,相较于创建后单独设置属性和绑定,这种方式带来的性能提升微乎其微。

以下是一个简单的 QML 组件定义示例:


import QtQuick 2.0
 
Rectangle { width: 80; height: 50; color: "red" }


在 main.qml 中导入了一个名为 componentCreation.js 的 JavaScript 文件,该文件负责创建 Sprite 对象:


import QtQuick 2.0
import "componentCreation.js" as MyScript
 
Rectangle 
{
    id: appWindow
    width: 300; height: 300
 
    Component.onCompleted: MyScript.createSpriteObjects();
}


componentCreation.js


var component;
var sprite;
 
function createSpriteObjects() 
{
    component = Qt.createComponent("Sprite.qml");
    if (component.status == Component.Ready)
        finishCreation();
    else
        component.statusChanged.connect(finishCreation);
}
 
function finishCreation() 
{
    if (component.status == Component.Ready) 
    {
        sprite = component.createObject(appWindow, {x: 100, y: 100});
        if (sprite == null) 
        {
            console.log("Error creating object");
        }
    } 
    else if (component.status == Component.Error) 
    {
        console.log("Error loading component:", component.errorString());
    }
}


当使用相对路径引用文件时,该路径应相对于执行 Qt.createComponent() 的文件位置。

此外,还可以利用 bateObject() 函数在不阻塞主线程的情况下实例化组件。

1.2、从 QML 字符串创建对象

利用 Qt.createQmlObject() 函数,可以直接从 QML 字符串构建 QML 对象,具体用法如下例所示:


const newObject = Qt.createQmlObject(`
    import QtQuick 2.0
    Rectangle 
    {
        color: "red"
        width: 20
        height: 20
    }
    `,
    parentItem,
    "myDynamicSnippet"
);


  • 第一个参数是需要创建的 QML 字符串内容。
  • 第二个参数指定新对象的父对象,其语义与组件的父参数一致,同样适用于 createQmlObject()。
  • 第三个参数是与新对象关联的文件路径,主要用于错误信息的报告。

若 QML 字符串中使用了相对路径来导入文件,则该路径应相对于定义父对象(即方法的第二个参数)的文件位置。

在构建静态 QML 应用程序时,系统会扫描 QML 文件以检测导入依赖项,从而在编译时解决所有必要的插件和资源。然而,这一机制仅处理显式导入语句(位于 QML 文件顶部的语句),并不包含字符串文字内部的导入语句。为了支持静态构建,用户需确保使用 Qt.createQmlObject() 的 QML 文件在文件顶部明确包含所有必要的导入,包括那些位于字符串文字内部的导入。

二、动态删除对象

在许多用户界面场景中,将可视对象的不透明度设置为 0 或将其移出屏幕往往足以满足需求。然而,当存在大量动态创建的对象时,及时删除未使用的对象能带来显著的性能优势。

特别注意:严禁手动删除由 QML 对象工厂(如 Loader 和 Repeater)动态创建的对象。同时,也应避免删除非自身动态创建的对象。

可以使用 destroy() 方法来移除项目。该方法包含一个可选参数(默认值为 0),用于指定销毁对象前的近似延迟时间(毫秒)。

示例:application.qml 创建了 SelfDestroyingRect.qml 组件的五个实例。每个实例执行一个 NumberAnimation,当动画结束时,调用其根对象上的 destroy() 以销毁自身:

application.qml


import QtQuick 2.0
 
Item 
{
    id: container
    width: 500; height: 100
 
    Component.onCompleted: 
    {
        var component = Qt.createComponent("SelfDestroyingRect.qml");
        for (var i=0; i<5; i++) 
        {
            var object = component.createObject(container);
            object.x = (object.width + 10) * i;
        }
    }
}


SelfDestroyingRect.qml


import QtQuick 2.0
 
Rectangle 
{
    id: rect
    width: 80; height: 80
    color: "red"
 
    NumberAnimation on opacity 
    {
        to: 0
        duration: 1000
 
        onRunningChanged: 
        {
            if (!running) 
            {
                console.log("Destroying...")
                rect.destroy();
            }
        }
    }
}
 

或者,application.qml 可以通过调用 object.destroy() 销毁创建的对象。

注意:对对象内部调用 destroy() 是安全的。对象并非在调用 destroy() 的瞬间立即销毁,而是在当前脚本块执行完毕与下一帧渲染之间的某个时刻被清除(除非指定了非零延迟)。

另外,如果 SelfDestroyingRect 实例是像这样静态创建的:


Item 
{
    SelfDestroyingRect 
    {
        // ...
    }
}


这将导致错误,因为对象仅在动态创建时才支持动态销毁。

通过 Qt.createQmlObject() 创建的对象也可以类似地使用 destroy() 进行销毁:


const newObject = Qt.createQmlObject(`
    import QtQuick 2.0
    Rectangle 
    {
        color: "red"
        width: 20
        height: 20
    }
    `,
    parentItem,
    "myDynamicSnippet"
);
newObject.destroy(1000);

至此,关于 JavaScript 中创建动态 QML 对象的方法介绍完毕。如需了解更多 JavaScript 创建动态 QML 对象的内容,请搜索本站历史文章或继续浏览后续相关文章。

作者最新文章