在JavaScript中动态的创建QML对象

在实际qml应用开发中,我们可以在javascript中动态的创建qml对象。这样做可以延迟对象的实例化,当我们在需要创建对象的时候才在javascript代码中创建,则可以缩短应用程序的启动时间,还可以动态创建可视对象,有助于提高应用程序性能。
创建动态对象
有两种方法可以在javascript代码中动态的创建对象。
第一种是:调用qt.createcomponent()来动态创建一个component对象;
第二种是:使用qt.createqmlobject()函数,以qml字符串的方式创建一个对象。
如果我们已经在qml文档中定义了一个现有组件,并希望可以动态地创建该组件实例,那么可选择第一种方法。当我们需要在运行时创建qml对象,应选择第二种方法。
下文将分别介绍这两种方法。
动态创建组件
要动态加载定义在qml文件中的组件,需调用qt对象中的qt.createcomponent()函数。这个函数将接收qml文件的url参数,并根据这个url创建一个component对象。
一旦创建了组件,则可以调用createobject()方法来创建该组件的一个实例。createobject()函数可以接收两个参数:
(1)参数一:第一个是新对象的父对象。父对象可以是图形对象(即item类型)或非图形对象(即qtobject或c++ qobject类型)。只有带有图形父对象的图形对象才会呈现到qt quick视觉画布中。如果想在后续设置父函数,我们可以将null传递给这个函数。
(2)参数二:第二个是可选参数,是的映射,用于定义对象的初始属性值。在创建对象之前,将此参数指定的属性值应用于对象,可以避免绑定错误。当然与在创建对象后定义属性值和属性绑定相比,这种方式在性能上有一些小的影响。
例如,这里有一个qml文件,名为mycomponent.qml,代表一个qml组件:
import qtquick 2.0rectangle { width: 80; height: 50; color: red }  
然后创建一个javascript脚本文件:componentcreation.js。用于检测在调用createobject()之前组件是否被创建好(如果qml文件是通过网络加载的,则不可能立即就准备好,故此处需要判断处理),如下代码:
var component;var sprite;function createspriteobjects() {    component = qt.createcomponent(mycomponent.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对象的子对象,并出现在界面中。
接着我们在main.qml文件中使用import componentcreation.js as myscript语句导入componentcreate.js文件,用于创建mycomponent对象:
import qtquick 2.0import componentcreation.js as myscriptrectangle {    id: appwindow    width: 300; height: 300    component.oncompleted: myscript.createspriteobjects();}  
如果需要将信号连接到动态创建对象的信号处理函数,需使用信号的connect()方法。
以qml字符串形式创建对象
在qml开发中,很多时候都会在运行时定义qml对象,这时候则可以使用qt.createqmlobject()函数来实现,在函数中指定qml字符串来创建一个qml对象,如下代码:
var newobject = qt.createqmlobject('import qtquick 2.0; rectangle {color: red; width: 20; height: 20}',parentitem,dynamicsnippet1);  
qt.createqmlobject()函数需要三个参数:
(1)第一个参数是要创建的qml字符串。其中的qml字符串就像在新qml文件中创建组件的编写方式一样。
(2)第二个参数是新对象的父对象。
(3)第三个参数是与新对象相关联的文件路径,用于报告错误信息。
【特别注意(一)】
如果qml字符串使用相对路径方式导入文件,则该路径应该相对于父对象(方法的第二个参数)所在的文件。
【特别注意(二)】
在构建静态qml应用程序时,qml引擎会扫描qml文件来检测导入依赖项。这样,所有必需的插件和资源都在编译时解析。但是,只考虑显式的import语句(在qml文件顶部找到的那些),而不会考虑包含在字符串文本中的import语句。因此,为了支持静态构建,我们需要在使用qt.createqmlobject()的qml文件中,还需要在文件顶部显式地包含所有的导入信息。
管理动态创建的对象
在管理动态创建的对象时,必须确保创建上下文的生命周期比创建的对象长。否则,如果创建上下文先被销毁,动态对象中的绑定和信号处理程序将会“罢工”。
实际的创建上下文取决于对象是如何创建的:
(1)如果使用了qt.createcomponent(),创建上下文就是在其中调用此方法的qqmlcontext。
(2)如果调用qt.createqmlobject(),创建上下文是传递给该方法的父对象的上下文。
(3)如果定义了一个component{}对象,并且在该对象上调用了createobject()或incubateobject(),那么创建上下文就是组件定义的上下文。
备注:虽然动态创建的对象可以像其他对象一样使用,但它们在qml中是没有id属性的。
删除动态对象
在大多数用户界面开发中,将可视对象的不透明度设置为0或将可视对象移出屏幕,则可以满足许多的开发需求了。但是,如果应用界面中有多个动态创建的对象,那么删除不使用的对象可能会获得较好性能。
但注意不要手动删除由qml对象工厂(如loader和repeater)动态创建的对象。另外还应该避免删除不是自己动态创建的对象。
我们可以使用destroy()方法删除item。该方法有一个可选参数(默认为0),用于指定对象被销毁前的延迟时间。
这里有一个例子:我们在application.qml文件中创建了selfdestroyingrect的五个实例组件。每个实例运行一个numberanimation,当animation完成时,调用它的根对象的destroy()来销毁,代码如下:
//application.qml
import qtquick 2.0item {    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.0rectangle {    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()的瞬间被销毁,而是在脚本块结束后的某个时刻被清除(非零延迟除外)。
在销毁对象时,需要注意对象只有在动态创建的情况下才能动态销毁。
对于使用qt.createqmlobject()创建的对象也可以使用destroy()销毁,例如下例javascript代码:
var newobject = qt.createqmlobject('import qtquick 2.0; rectangle {color: red; width: 20; height: 20}',                                   parentitem,                                   dynamicsnippet1);newobject.destroy(1000);


亚马逊深入汽车领域
Graphcore发布IPU开发者云 给中国AI开发者带来一大助力
当今社会下我们对医疗机器人的疯狂渴望
高通骁龙810抢先看:64位八核,20nm工艺
avx钽电容的应用能够为我们解决哪些麻烦
在JavaScript中动态的创建QML对象
如何判断集成电路IC是否“有问题”
磁致伸缩式、双法兰差压式和干簧电阻式液位变送器的比较
NVIDIA因配送机器人将设立独立事业部预计两年后市场成熟
索尼XperiaXZP推限量版618套,只卖出去400多套,这或许是史上最尴尬的旗舰特别版机型了吧!
微生物限度检测仪的应用以及特性的说明
高通推出QCS400系列智能音频芯片 主要用于智能音箱和显示器
5个激光、超声波测距方案设计
检具三维扫描仪+3D打印做产品质量检测
家庭影院套装的视频端口
总投资288亿元,长电、艾为等12个项目在上海临港集中开工
ARM架构服务器芯片发展的困难,中国或有助于ARM打破Intel的垄断地位
如何使用HyperledgeFabric网络react.js来构建Web应用程序
苹果的自研5G,又得再等等了
射频标签(RFID)的静电控制解决方案