qml 动态创建对象

在JavaScript中动态创建对象有两种方式.可调用Qt.createComponent()动态创建一个组件对象,或使用Qt.createQmlObject()从一个描述QML的字符串创建元素.最好是有一个定义在.qml文件中的组件,需要动态创建这个组件的实例.否则,就需要在运行时使用一个QML描述字符串创建元素.

动态创建组件
要动态加载QML文件中的组件,可在QML全局对象中调用Qt.createComponent()函数.这个函数只有一个指向QML文件的URL参数并创建这个URL指向的组件对象.
创建了组件后,可以调用其createObject()方法创建组件的实例.这个函数有一个或两个参数:
第一个参数是新元素的parent.由于图形项(graphical item)在场景中必须有parent,否则就无法显示,还是推荐使用这种方式设置一个parent.然而,如果希望稍后在设置可以传递一个null实参.
第二个参数是可选的属性名称-值的映射列表,用来初始化元素的属性值.这个参数指定的属性值在对象构造完成之前被赋给对象的属性,避免了有些属性在用于绑定前必须被初始化而发生的错误.在属性用于绑定前就已经设置了值.另外,与对象创建后再设置属性值和绑定相比,具有稍微的效率优势.

下面是一个范例,首先定义Sprite.qml文件:

 import QtQuick 1.0

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

主应用程序文件是main.qml,导入可创建Spite对象的componentCreation.js JavaScript文件:

 import QtQuick 1.0
 import "componentCreation.js" as MyScript

 Rectangle {
   id: appWindow
   width: 300; height: 300

   Component.onCompleted: MyScript.createSpriteObjects();
 }

下面是componentCreation.js. 注意在调用createObject()前先判断组件状态是否为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,使新创建的对象作为main.qml中的appWindow对象的子对象.否则,新创建的对象不会在场景中显示.
当用相对路径引用文件时,路径是相对于执行Qt.CreatComponent()函数的文件而言的.
要连接动态创建对象上的信号(或槽),可使用信号的connect()方法.

基于QML的字符串创建对象

如果在运行时还没有建立QML文件,可以使用Qt.CreateQmlObject()函数使用QML描述字符串来创建QML对象,如下所示:

 var newObject = Qt.createQmlObject('import QtQuick 1.0; Rectangle {color: "red"; width: 20; height: 20}',
   parentItem, "dynamicSnippet1");

第一个参数是创建QML的字符串.与创建新的QML文件一样,需要导入必要的类型.第二个参数是新对象的parent;这个parent必须在场景中存在.第三个参数新对象相关的文件连接,用于导出错误报表.
如果QML中使用相对路径导入文件,路径是相对于定义了parent对象的文件而言的.