QML概念及框架--QML動態對象管理

    QML提供了很多方法來動態創建和管理QML對象。如Loader、RePeater、ListView、GridView和PathView等元素都支持動態對象管理。對象也可以在C++中被創建和管理,這是混合QML/C++應用程序的首選方式。QML也支持在JavaScript代碼中動態創建對象,這在現有的QML元素不適合應用程序需要的情況下是很有用的,而且也不需要涉及C++組件。

1. 動態創建對象

    這裏有兩種方法從JavaScript動態創建對象。既可以調用Qt.createComponent()來動態創建Compont對象,也可以使用Qt.createQmlObject()從QML字符串來創建對象。如果已經有一個在.qml文件中定義的組件,而且希望冬天創建該組件的一個實例,那麼使用第一種方法是比較好的;如果QML本身是在運行時產生的,那麼使用QML字符串來創建對象是很有用的。

    (1) 動態創建一個組件

    要動態加載定義在一個QML文件中的組件,可以在QML全局對象上調用Qt.createComponent()函數。這個函數需要將QML文件的URL作爲其參數,然後這個URL上創建一個Component對象。一旦有了一個Component,就可以調用它的createObject()函數來創建該組件的一個實例。這個函數需要指定新對象的父對象。因爲圖形項目沒有父對象是無法顯示在場景上的,所以建議這樣來設置父對象。然而,如果像稍後再爲其設置父對象,可以安全的設置null作爲該函數的參數。

    QML組件Sprite.qml

import QtQuick 2.4

Rectangle { width: 80; height: 50; color: "red" }
  導入JavaScript文件componentCreation.js來創建Sprite對象:
import QtQuick 2.4
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(appWidow)
        if(sprite == null) {
            //錯誤處理
        } else {
            sprite.x = 100
            sprite.y = 100
            //...
        }
    } else if(componet.status == Component.Error) {
        //錯誤處理
        console.log("Error loading component:", component.errorString())
    }
}
    如果可以確保QML文件是從本地文件加載的,那麼可以忽略finishCreation()函數,而在createSpriteObject()函數中立即調用createObject()函數,上面的可以寫成

function createSpriteObjects() {
    component Qt.createComponent("Sprite.qml")
    sprite = component.createObject(appWindow)
    if(sprite == null) {
        //Erro Handling
        console.log("Erro creating object");
    } else {
        sprite.x = 100
        sprite.y = 100
        //...
    }
}

    注意,這裏createObject()使用appWindow作爲參數,所以創建的對象會成爲main.qml中appWindow的子對象。當使用相對路徑來加載文件時,需要是相對於執行Qt.createComponent()的文件的路徑。將信號關聯到 動態創建的對象上,或者從動態創建的對象上接收信號,都要使用信號的connect()函數。

    (2) 從QML字符串創建一個對象

    如果QML直到運行時才被定義,可以使用Qt.createQmlObject()函數從一個QML字符串創建一個QML對象。

var newObject = Qt.createQmlObject(
    'import QtQuick 2.4; Rectangle{color: "red"; width: 20; height:20}', parentItem, "dynamicSnippet1");
    第一個參數是要創建的QML字符串,就像一個新的文件一樣,需要導入所需要的類型;第二個參數是父對象,需要在場景中已經存在的一個對象;第三個參數是於新對象相關文件的路徑,用來報告錯誤。如果在QML字符串中導入的文件使用的是相對路徑,那麼需要相對於定義父對象的文件的路徑。

2. 文虎動態創建的對象

   當管理動態創建的對象是,必須確保創建上下文(creation context)不會再創建的對象銷燬前被銷燬。否則,如果創建上下文被首先銷燬,那麼在動態創建對象中的綁定將不會再工作。實際的創建上下文依賴於對象是怎樣被創建的:

    a.  如果使用了Qt.createComponent(),創建上下文就是調用該函數的QDeclarativeContext;

    b. 如果使用了Qt.crateQmlObject(),創建上下文就是父對象的上下文

    c. 如果定義了一個Component{},然後在其上調用了createObject(),創建上下文就是該Component中定義的上下文

    另外需注意,雖然動態創建的對象可以像其他對象一樣來使用,但是它們沒有id值。

3. 動態刪除對象

    在很多用戶界面中,將圖形項的透明度設置爲0或者將其移除屏幕就夠了,而不需要將其刪除。然而,如果有很多動態生成的對象,難麼將不用的對象刪除會得到一個很大的性能提升。不過應該注意,永遠不要手動刪除通過QML元素(例如Loader和Repeater)動態生成的對象,不要刪除不是自己動態創建的對象。

    可以使用destroy()函數來刪除對象,這個函數有一個可選參數,可以用來設置在銷燬該對象以前的以毫秒爲單位的延遲時間,該參數默認爲0.在下面列子中,application.qml中創建了SelfDestroyingRect.qml組件的5個實例,每一個實例運行一個NumberAnimation,當動畫結束時在其根對象上調用destroy()來進行自我銷燬。

    application.qml文件:

import QtQuick 2.4

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<pre name="code" class="html">Item {
    SelfDestroyingRect{...}
}

Rectangle { id: rect width: 80; height: 80 color: "red" NumberAnimation on opacity { to: 0 duration: 1000 onRunningChanged: { if(! runnig) { console.log("Destroying ...") rect.destroy(); } } }}

    另外,application.qml可以調用object.destroy()類銷燬創建的對象。在一個對象內部調用destroy()來銷燬自己是安全的。對象不會再destroy()被調用時就被銷燬,耳屎在該腳本塊的末尾和下一幀之間的某個時間進行清理(除非將延時指定了一個非零值)。

     注意,如果SelfDestroyRect實例被靜態的創建

Item {
    SelfDestroyingRect{...}
}
   這樣會產生錯誤,只有動態創建的對象纔可以被動態刪除。使用Qt.createQmlObject()創建的對象可以相似的使用destroy()來刪除

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






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章