在實(shí)際QML應(yīng)用開(kāi)發(fā)中,我們可以在JavaScript中動(dòng)態(tài)的創(chuàng)建QML對(duì)象。這樣做可以延遲對(duì)象的實(shí)例化,當(dāng)我們?cè)谛枰獎(jiǎng)?chuàng)建對(duì)象的時(shí)候才在JavaScript代碼中創(chuàng)建,則可以縮短應(yīng)用程序的啟動(dòng)時(shí)間,還可以動(dòng)態(tài)創(chuàng)建可視對(duì)象,有助于提高應(yīng)用程序性能。
創(chuàng)建動(dòng)態(tài)對(duì)象
有兩種方法可以在JavaScript代碼中動(dòng)態(tài)的創(chuàng)建對(duì)象。
第一種是:調(diào)用Qt.createComponent()來(lái)動(dòng)態(tài)創(chuàng)建一個(gè)Component對(duì)象;
第二種是:使用Qt.createQmlObject()函數(shù),以QML字符串的方式創(chuàng)建一個(gè)對(duì)象。
如果我們已經(jīng)在QML文檔中定義了一個(gè)現(xiàn)有組件,并希望可以動(dòng)態(tài)地創(chuàng)建該組件實(shí)例,那么可選擇第一種方法。當(dāng)我們需要在運(yùn)行時(shí)創(chuàng)建QML對(duì)象,應(yīng)選擇第二種方法。
下文將分別介紹這兩種方法。
動(dòng)態(tài)創(chuàng)建組件
要?jiǎng)討B(tài)加載定義在QML文件中的組件,需調(diào)用Qt對(duì)象中的Qt.createcomponent()函數(shù)。這個(gè)函數(shù)將接收QML文件的URL參數(shù),并根據(jù)這個(gè)URL創(chuàng)建一個(gè)Component對(duì)象。
一旦創(chuàng)建了組件,則可以調(diào)用createObject()方法來(lái)創(chuàng)建該組件的一個(gè)實(shí)例。createObject()函數(shù)可以接收兩個(gè)參數(shù):
(1)參數(shù)一:第一個(gè)是新對(duì)象的父對(duì)象。父對(duì)象可以是圖形對(duì)象(即Item類(lèi)型)或非圖形對(duì)象(即QtObject或C++ QObject類(lèi)型)。只有帶有圖形父對(duì)象的圖形對(duì)象才會(huì)呈現(xiàn)到Qt Quick視覺(jué)畫(huà)布中。如果想在后續(xù)設(shè)置父函數(shù),我們可以將null傳遞給這個(gè)函數(shù)。
(2)參數(shù)二:第二個(gè)是可選參數(shù),是<屬性-值>的映射,用于定義對(duì)象的初始屬性值。在創(chuàng)建對(duì)象之前,將此參數(shù)指定的屬性值應(yīng)用于對(duì)象,可以避免綁定錯(cuò)誤。當(dāng)然與在創(chuàng)建對(duì)象后定義屬性值和屬性綁定相比,這種方式在性能上有一些小的影響。
例如,這里有一個(gè)qml文件,名為MyComponent.qml,代表一個(gè)QML組件:
importQtQuick2.0
Rectangle{width:80;height:50;color:"red"}
然后創(chuàng)建一個(gè)JavaScript腳本文件:componentCreation.js。用于檢測(cè)在調(diào)用createObject()之前組件是否被創(chuàng)建好(如果QML文件是通過(guò)網(wǎng)絡(luò)加載的,則不可能立即就準(zhǔn)備好,故此處需要判斷處理),如下代碼:
varcomponent; varsprite; functioncreateSpriteObjects(){ component=Qt.createComponent("MyComponent.qml"); if(component.status==Component.Ready) finishCreation(); else component.statusChanged.connect(finishCreation); } functionfinishCreation(){ if(component.status==Component.Ready){ sprite=component.createObject(appWindow,{x:100,y:100}); if(sprite==null){ //ErrorHandling console.log("Errorcreatingobject"); } }elseif(component.status==Component.Error){ //ErrorHandling console.log("Errorloadingcomponent:",component.errorString()); } }
在實(shí)際的開(kāi)發(fā)中,基本上都是從本地加載qml文件,這時(shí)候則可以省略finishCreation()函數(shù),立即調(diào)用createObject(),例如下例代碼:
functioncreateSpriteObjects(){
component=Qt.createComponent("Sprite.qml");
sprite=component.createObject(appWindow,{x:100,y:100});
if(sprite==null){
//ErrorHandling
console.log("Errorcreatingobject");
}
}
注意,上面例子中,createObject()都是在appWindow作為父參數(shù)傳遞的情況下調(diào)用的,因?yàn)閯?dòng)態(tài)創(chuàng)建的對(duì)象是一個(gè)可視化對(duì)象。創(chuàng)建的對(duì)象將成為main.qml中的appWindow對(duì)象的子對(duì)象,并出現(xiàn)在界面中。
接著我們?cè)趍ain.qml文件中使用import "componentCreation.js" as MyScript語(yǔ)句導(dǎo)入componentcreate.js文件,用于創(chuàng)建MyComponent對(duì)象:
importQtQuick2.0
import"componentCreation.js"asMyScript
Rectangle{
id:appWindow
width:300;height:300
Component.onCompleted:MyScript.createSpriteObjects();
}
如果需要將信號(hào)連接到動(dòng)態(tài)創(chuàng)建對(duì)象的信號(hào)處理函數(shù),需使用信號(hào)的connect()方法。
以QML字符串形式創(chuàng)建對(duì)象
在QML開(kāi)發(fā)中,很多時(shí)候都會(huì)在運(yùn)行時(shí)定義QML對(duì)象,這時(shí)候則可以使用Qt.createQmlObject()函數(shù)來(lái)實(shí)現(xiàn),在函數(shù)中指定QML字符串來(lái)創(chuàng)建一個(gè)QML對(duì)象,如下代碼:
varnewObject=Qt.createQmlObject('importQtQuick2.0;Rectangle{color:"red";width:20;height:20}',parentItem,"dynamicSnippet1");
Qt.createQmlObject()函數(shù)需要三個(gè)參數(shù):
(1)第一個(gè)參數(shù)是要?jiǎng)?chuàng)建的QML字符串。其中的QML字符串就像在新qml文件中創(chuàng)建組件的編寫(xiě)方式一樣。
(2)第二個(gè)參數(shù)是新對(duì)象的父對(duì)象。
(3)第三個(gè)參數(shù)是與新對(duì)象相關(guān)聯(lián)的文件路徑,用于報(bào)告錯(cuò)誤信息。
【特別注意(一)】
如果QML字符串使用相對(duì)路徑方式導(dǎo)入文件,則該路徑應(yīng)該相對(duì)于父對(duì)象(方法的第二個(gè)參數(shù))所在的文件。
【特別注意(二)】
在構(gòu)建靜態(tài)QML應(yīng)用程序時(shí),QML引擎會(huì)掃描QML文件來(lái)檢測(cè)導(dǎo)入依賴(lài)項(xiàng)。這樣,所有必需的插件和資源都在編譯時(shí)解析。但是,只考慮顯式的import語(yǔ)句(在QML文件頂部找到的那些),而不會(huì)考慮包含在字符串文本中的import語(yǔ)句。因此,為了支持靜態(tài)構(gòu)建,我們需要在使用Qt.createQmlObject()的QML文件中,還需要在文件頂部顯式地包含所有的導(dǎo)入信息。
管理動(dòng)態(tài)創(chuàng)建的對(duì)象
在管理動(dòng)態(tài)創(chuàng)建的對(duì)象時(shí),必須確保創(chuàng)建上下文的生命周期比創(chuàng)建的對(duì)象長(zhǎng)。否則,如果創(chuàng)建上下文先被銷(xiāo)毀,動(dòng)態(tài)對(duì)象中的綁定和信號(hào)處理程序?qū)?huì)“罷工”。
實(shí)際的創(chuàng)建上下文取決于對(duì)象是如何創(chuàng)建的:
(1)如果使用了Qt.createComponent(),創(chuàng)建上下文就是在其中調(diào)用此方法的QQmlContext。
(2)如果調(diào)用Qt.createQmlObject(),創(chuàng)建上下文是傳遞給該方法的父對(duì)象的上下文。
(3)如果定義了一個(gè)Component{}對(duì)象,并且在該對(duì)象上調(diào)用了createObject()或incubateObject(),那么創(chuàng)建上下文就是組件定義的上下文。
備注:雖然動(dòng)態(tài)創(chuàng)建的對(duì)象可以像其他對(duì)象一樣使用,但它們?cè)赒ML中是沒(méi)有id屬性的。
刪除動(dòng)態(tài)對(duì)象
在大多數(shù)用戶(hù)界面開(kāi)發(fā)中,將可視對(duì)象的不透明度設(shè)置為0或?qū)⒖梢晫?duì)象移出屏幕,則可以滿(mǎn)足許多的開(kāi)發(fā)需求了。但是,如果應(yīng)用界面中有多個(gè)動(dòng)態(tài)創(chuàng)建的對(duì)象,那么刪除不使用的對(duì)象可能會(huì)獲得較好性能。
但注意不要手動(dòng)刪除由QML對(duì)象工廠(如Loader和Repeater)動(dòng)態(tài)創(chuàng)建的對(duì)象。另外還應(yīng)該避免刪除不是自己動(dòng)態(tài)創(chuàng)建的對(duì)象。
我們可以使用destroy()方法刪除Item。該方法有一個(gè)可選參數(shù)(默認(rèn)為0),用于指定對(duì)象被銷(xiāo)毀前的延遲時(shí)間。
這里有一個(gè)例子:我們?cè)赼pplication.qml文件中創(chuàng)建了SelfDestroyingRect的五個(gè)實(shí)例組件。每個(gè)實(shí)例運(yùn)行一個(gè)NumberAnimation,當(dāng)animation完成時(shí),調(diào)用它的根對(duì)象的destroy()來(lái)銷(xiāo)毀,代碼如下:
//application.qml
importQtQuick2.0
Item{
id:container
width:500;height:100
Component.onCompleted:{
varcomponent=Qt.createComponent("SelfDestroyingRect.qml");
for(vari=0;i<5;?i++)?{
????????????var?object?=?component.createObject(container);
????????????object.x?=?(object.width?+?10)?*?i;
????????}
????}
}
//SelfDestroyingRect.qml
importQtQuick2.0
Rectangle{
id:rect
width:80;height:80
color:"red"
NumberAnimationonopacity{
to:0
duration:1000
onRunningChanged:{
if(!running){
console.log("Destroying...")
rect.destroy();
}
}
}
}
另外,application.qml可以調(diào)用object.destroy()來(lái)銷(xiāo)毀已創(chuàng)建的對(duì)象。
備注:上述代碼中,調(diào)用對(duì)象的destroy()是安全的。因?yàn)閷?duì)象不會(huì)在調(diào)用destroy()的瞬間被銷(xiāo)毀,而是在腳本塊結(jié)束后的某個(gè)時(shí)刻被清除(非零延遲除外)。
在銷(xiāo)毀對(duì)象時(shí),需要注意對(duì)象只有在動(dòng)態(tài)創(chuàng)建的情況下才能動(dòng)態(tài)銷(xiāo)毀。
對(duì)于使用Qt.createQmlObject()創(chuàng)建的對(duì)象也可以使用destroy()銷(xiāo)毀,例如下例JavaScript代碼:
varnewObject=Qt.createQmlObject('importQtQuick2.0;Rectangle{color:"red";width:20;height:20}',
parentItem,
"dynamicSnippet1");
newObject.destroy(1000);
審核編輯:劉清
-
URL
+關(guān)注
關(guān)注
0文章
142瀏覽量
16174 -
JAVA語(yǔ)言
+關(guān)注
關(guān)注
0文章
138瀏覽量
21434 -
javascript
+關(guān)注
關(guān)注
0文章
525瀏覽量
56157
原文標(biāo)題:“神級(jí)”般的QML開(kāi)發(fā)技巧,學(xué)會(huì)了
文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
探索DS9638QML:高性能RS - 422雙高速差分線(xiàn)驅(qū)動(dòng)器
RTThread線(xiàn)程退出后rt_malloc動(dòng)態(tài)創(chuàng)建的資源沒(méi)有釋放怎么解決?
RT-Thread Nano移植后動(dòng)態(tài)創(chuàng)建線(xiàn)程創(chuàng)建不了怎么解決?
rtth studio中nano 如何創(chuàng)建動(dòng)態(tài)線(xiàn)程?
rtt studio中nano 如何創(chuàng)建動(dòng)態(tài)線(xiàn)程?
一種適用于動(dòng)態(tài)環(huán)境的自適應(yīng)先驗(yàn)場(chǎng)景-對(duì)象SLAM框架
?LM136A-2.5QML/LM136A-2.5QML-SP 技術(shù)文檔摘要
?LM4050QML精密微功耗并聯(lián)電壓基準(zhǔn)芯片技術(shù)文檔總結(jié)
PLL技術(shù)在FPGA中的動(dòng)態(tài)調(diào)頻與展頻功能應(yīng)用
RT-Thread Nano移植后動(dòng)態(tài)創(chuàng)建線(xiàn)程創(chuàng)建不了怎么處理?
[Actor] 通過(guò)actor創(chuàng)建控制中心與數(shù)據(jù)采集工作站來(lái)看操作者架構(gòu)
為什么在SDK 1.3.5中創(chuàng)建的配置文件是在SDK 1.3.4中創(chuàng)建的 打不開(kāi)?
ADC08D1520QML可以采集到的最高頻率是多少?
SciChart—高性能的JavaScript圖表和圖形庫(kù)
Spire.XLS for JavaScript——多功能JavaScript電子表格庫(kù)(一)
在JavaScript中動(dòng)態(tài)的創(chuàng)建QML對(duì)象
評(píng)論