通过 JavaScript 动态创建 QML 对象
QML 支持通过 JavaScript 动态创建对象。这有助于将对象的实例化推迟到必要时,从而缩短应用程序的启动时间。此外,它还允许根据用户输入或其他事件,动态创建视觉对象并将其添加到场景中。
警告: 不应从未经信任的来源动态创建对象 。静态 QML 源的限制同样适用于动态对象创建。
动态创建对象
有两种方法可以通过 JavaScript 动态创建对象。您可以调用 `Qt.createComponent()` 来动态创建 `Component ` 对象,或者使用 `Qt.createQmlObject()` 根据 QML 字符串创建对象。如果您在 QML 文档中已定义了某个组件,并希望动态创建该组件的实例,则创建组件是更好的选择。 否则,当组件的 QML 代码本身是在运行时生成的,从 QML 字符串创建对象会非常有用。
动态创建组件
要动态加载在 QML 文件中定义的组件,请调用 `Qt object` 中的 `Qt.createComponent()` 函数。该函数仅接受 QML 文件的 URL 作为参数,并根据该 URL 创建一个 `Component ` 对象。
获得Component 对象后,可调用其createObject()方法来创建该组件的实例。该函数可接受一个或两个参数:
- 第一个参数是新对象的父对象。父对象可以是图形对象(即Item 类型),也可以是非图形对象(即QtObject 或 C++QObject 类型)。只有具有图形父对象的图形对象才会被渲染到 Qt Quick 视觉画布上。若希望稍后设置父对象,可安全地将 `
null` 传递给此函数。 - 第二个参数是可选的,它是一个属性-值对映射,用于定义对象的任何初始属性值。由该参数指定的属性值会在对象创建完成之前应用到对象上,从而避免了因某些属性必须初始化才能启用其他属性绑定而可能发生的绑定错误。 此外,与在对象创建后定义属性值和绑定相比,此方法在性能上略有优势。
以下是一个示例。首先是 `Sprite.qml`,它定义了一个简单的 QML 组件:
import QtQuick
Rectangle { width: 80; height: 50; color: "red" }我们的主应用程序文件 `main.qml` 导入了 JavaScript 文件 `componentCreation.js `,该文件将创建 `Sprite ` 对象:
import QtQuick
import "componentCreation.js" as MyScript
Rectangle {
id: appWindow
width: 300; height: 300
Component.onCompleted: MyScript.createSpriteObjects();
}以下是componentCreation.js 文件。请注意,它会在调用createObject()之前,先检查status 组件是否为Component.Ready ,以防QML文件通过网络加载而无法立即就绪。
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) {
// Error Handling
console.log("Error creating object");
}
} else if (component.status == Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}
}如果您确定要加载的 QML 文件是本地文件,则可以省略finishCreation() 函数,并立即调用createObject():
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
}请注意,在两种情况下,调用createObject()时都会将appWindow 作为父对象参数传递,因为动态创建的对象是一个视觉对象(Qt Quick )。该对象将成为main.qml 中appWindow 对象的子对象,并出现在场景中。
使用相对路径的文件时,该路径应相对于执行Qt.createComponent() 的文件。
要将信号连接到(或从)动态创建的对象,请使用信号的connect() 方法。有关更多信息,请参阅“将信号连接到方法和信号”。
还可以通过incubateObject() 函数在不阻塞的情况下实例化组件。
从 QML 字符串创建对象
警告: 从 QML 字符串创建 对象的速度极其缓慢,因为每次执行时引擎都必须编译传入的 QML 字符串。 此外,在程序化构建 QML 代码时,很容易生成无效的 QML 代码。与通过字符串操作生成新组件相比,将 QML 组件保存在单独的文件中,并通过添加属性和方法来定制其行为要好得多。
如果 QML 代码在运行时才被定义,您可以使用 `Qt.createQmlObject()` 函数从 QML 字符串创建 QML 对象,如下例所示:
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);第一个参数是要创建的 QML 字符串。 与新建文件一样,你需要导入想要使用的任何类型。第二个参数是新对象的父对象,适用于组件的父对象语义同样适用于createQmlObject() 。第三个参数是与新对象关联的文件路径;该路径用于错误报告。
如果 QML 字符串使用相对路径导入文件,则该路径应以定义父对象(该方法的第二个参数)的文件为基准。
重要提示:在构建 静态 QML应用程序时, 系统会扫描 QML 文件以检测导入依赖关系。这样,所有必要的插件和资源都会在编译时得到解析。但是,系统仅会考虑显式的导入语句(即位于 QML 文件顶部的那些),而不会考虑包含在字符串字面量中的导入语句。 因此,为了支持静态构建,您需要确保使用Qt.createQmlObject() 的 QML 文件,除了在字符串字面量内部,还应在文件开头显式包含所有必要的导入语句。
维护动态创建的对象
在管理动态创建的对象时,必须确保创建上下文的存活时间长于所创建的对象。否则,如果创建上下文先被销毁,动态对象中的绑定和信号处理程序将不再起作用。
具体的创建上下文取决于对象的创建方式:
- 如果使用 `Qt.createComponent()`,则创建上下文即为调用该方法的 `QQmlContext `
- 如果调用 `Qt.createQmlObject()`,则创建上下文即为传递给该方法的父对象的上下文
- 如果定义了一个
Component{}对象,并在该对象上调用createObject()或incubateObject(),则创建上下文是定义该Component的上下文
此外,请注意,虽然动态创建的对象与其他对象的使用方式相同,但在 QML 中它们没有 id。
动态删除对象
在许多用户界面中,将视觉对象的不透明度设置为 0 或将视觉对象移出屏幕,就足以代替删除它。但是,如果您有大量动态创建的对象,删除未使用的对象可能会带来显著的性能提升。
请注意,切勿手动删除由 QML 便利对象生成器(如Loader 和Repeater )动态创建的对象。此外,应避免删除非您自己动态创建的对象。
可以使用destroy() 方法删除项。该方法有一个可选参数(默认值为 0),用于指定在对象被销毁之前的大致延迟时间(以毫秒为单位)。
以下是一个示例。application.qml 创建了五个SelfDestroyingRect.qml 组件的实例。每个实例都会运行一个NumberAnimation ,当动画结束时,会调用其根对象上的destroy() 来销毁自身:
application.qml | |
SelfDestroyingRect.qml | |
此外,application.qml 也可以通过调用object.destroy() 来销毁创建的对象。
请注意,在对象内部调用其 `destroy()` 方法是安全的。对象不会在调用 `destroy()` 的瞬间被销毁,而是在该脚本块结束与下一帧之间某个时间点被清理(除非您指定了非零延迟)。
另请注意,如果SelfDestroyingRect 实例是像这样静态创建的:
Item {
SelfDestroyingRect {
// ...
}
}这将导致错误,因为只有动态创建的对象才能被动态销毁。
使用 `Qt.createQmlObject()` 创建的对象同样可以通过 `destroy()` 进行销毁:
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);
newObject.destroy(1000);© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.