QML中有多种方式来动态创建和管理QML对象:
- Loader (加载器)
- Repeater(复制器)
- ListView,GridWiew,PethView(视图) (之后会介绍)
使用加载器:
Rectangle{
id:rect1
width: 100
height: 100
color: "blue"
Component{
id:com1
Rectangle{
height: 50
width: 50
color: "red"
}
}
}
Loader{sourceComponent: com1}//加载一个com1
使用复制器:
Grid{
spacing: 10
columns: 5//五列
//复制器
Repeater{
model:25//生成25个
Rectangle{
width:50;height: 50
color: "lightGreen"
Text{
anchors.centerIn: parent
font{bold: true;pixelSize: 20}
text:index//获取编号
}
}
}
}
使用JavaScript代码创建动态QML对象:
QML支持从JavaScript中动态创建对象。这对于在必要时延迟对象的实例化非常有用,从而缩短应用程序启动时间。它还允许动态创建视觉对象并将其添加到场景中,以响应用户输入或其他事件
动态创建对象的方法:
- 调用Qt.createComponent()来动态创建Component对象
- 使用Qt.createQmlObject() 从QML字符串创建对象,
- 如果在 QML 文档中定义了现有组件,并且希望动态创建该组件的实例,则创建组件会更好。否则,当对象 QML 本身在运行时生成时,从 QML 字符串创建对象很有用。
动态创建组件:
要动态加载 QML 文件中定义的组件,请在 Qt对象中调用 Qt.createComponent() 函数。此函数将 QML 文件的 URL 作为其唯一参数,并从此 URL 创建Component对象。
拥有组件之后,可以调用createObject()函数创建该组件的一个实例,此函数可以接收一个或两个参数:
- 指定新对象的父对象:父对象可以是图形对象或非图形对象。只有具有图形父对象的图形对象才会渲染到 QtQuick 可视化画布。如果您希望稍后设置父级,则可以安全地设置null作为函数参数。
- (可选参数)是定义对象的初始任何属性值的属性-值对的映射。此参数指定的属性值在对象创建完成之前应用于对象,从而避免在必须初始化特定属性以启用其他属性绑定时可能发生的绑定错误。此外,与在创建对象后定义属性值和绑定相比,性能优势很小。
使用时需要注意的情况:
QML文件可以有两种:
- 本地文件的话可以直接创建实例,不需要等待
- 如果是网上加载的文件的话,需要判断component的状态,就绪后才能创建实例
创建一个 myWidget.qml文件
import QtQuick 2.9
Rectangle{
width: 100;height: 100;color: "red"
}
主qml文件
import QtQuick 2.9
import "textJs.js" as Logic//导入js文件
import QtQuick.Window 2.2
Window {
id:window1
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
id:appWindow
width: 300;
height: 300
color: "lightBlue"
Component.onCompleted: Logic.createSpriteObjects()//调用函数
}
}
textJs.js文件
var component;//接收创建的对象
var sprite;//接收实例
function createSpriteObjects() {
component = Qt.createComponent("myWidget.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 直到运行时才定义,则可以使用 Qt.createQmlObject() 函数从 QML 字符串创建 QML 对象
Qt.createQmlObject(参数1,参数2,参数3)
- 参数1:创建的QML字符
- 参数2:父类
- 参数3:要与新对象关联的文件路径;这用于错误报告
var newObject = Qt.createQmlObject
('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
parentItem,
"dynamicSnippet1");
维护动态创建的对象:
管理动态创建的对象时,必须确保创建上下文的寿命超过创建的对象。否则,如果首先销毁创建上下文,则动态对象中的绑定和信号处理程序将不再工作。
创建上下文取决于对象的创建方式:
- 使用Qt.createComponent(),则创建上下文是调用此方法的QQmlContext
- 使用Qt.createQmlObject(),则创建上下文是传递给此方法的父对象的上下文
- 如果定义了一个Conponent{},然后在其上调了createObject(),创建上下文就是该Component
另外,请注意,虽然动态创建的对象可能与其他对象相同,但它们在 QML 中没有 id。
动态删除对象:
在许多用户界面中,将可视对象的不透明度设置为 0 或将可视对象移出屏幕而不是将其删除就足够了。但是,如果您有大量动态创建的对象,则删除未使用的对象可能会获得有价值的性能优势。
请注意,切勿手动删除由方便的 QML 对象工厂(如加载程序和转发器)动态创建的对象。此外,还应避免删除不是您自己动态创建的对象。
使用destroy()函数来删除对象,这个函数有一个可选的参数,可以用来设置在销毁该对象前的延迟时间(毫秒),默认为0。
例子:
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();//销毁对象
}
}
}
}
使用:Qt.createQmlObject()创建的对象同样可以使用destroy()销毁
var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
parentItem,
"dynamicSnippet1");
newObject.destroy(1000);
参考文档:
Dynamic QML Object Creation from JavaScript | Qt QML 5.15.12