1. 程式人生 > >【QT】QML如何建立動態元件

【QT】QML如何建立動態元件

QML動態元件指的是按需分配,需要時我們就建立一個自定義元件,也就是所謂的物件延遲例項化,而不是在程式一開始就建立它,不需要時我們就把它銷燬以節約記憶體,而不是傳統意義上的隱藏或覆蓋。我們可以使用ComponentLoader,也可以使用JavaScript的形式來完成。

先來介紹一下Component——

progress屬性,載入元件的過程,從0.01.0變化。

status屬性,載入元件的狀態,其列舉值分別是Component.Null/Ready/Loading/Error

url屬性,元件路徑。

completed()附加訊號,物件例項化完成後觸發。

destruction()附加訊號,物件開始銷燬時觸發。

object createObject(Itemparent, object properties)函式,建立物件。

string errorString()函式,錯誤描述。

object incubateObject(Itemparent, object properties,enumerationmode)函式,通過mode引數來非同步或同步建立物件,mode的值可以是Qt.ASynchronous/Synchronous,預設為非同步,返回值的屬性有statusobjectonStatusChangedforceCompletion(),其中

forceCompletion()函式強制同步建立物件。

再來看一下Loader——

active屬性,預設為true,設定成false時將不能載入元件。

asynchronous屬性,預設為false,設定成true時非同步載入元件。

item屬性,只讀屬性,儲存了成功載入的元件。

progress屬性,只讀屬性,從0.01.0變化。

source屬性,載入的元件是一個獨立的QML檔案。

sourceComponent屬性,在同一個QML檔案中載入元件。

status屬性,載入元件的狀態,其列舉值分別是Loader.Null/Ready/Loading/Error

loaded()訊號,元件成功載入時觸發。

object setSource(urlsource, object properties

)函式,設定預載入元件路徑。

在同一個QML檔案中使用ComponentLoader——

Component可封裝我們想要的東西,對外只提供一個定義好的介面,也就是其id屬性,然後我們就可以重複使用它了。如果某個QML檔案重複使用的Component比較小,或者說Component在邏輯上屬於某個QML檔案,那麼該Component就應該在這個QML檔案中定義,此時的Loader用到的就是其sourceComponent屬性,如下例子:

import QtQuick 2.2

Rectangle {
    width: 360; height: 360
    color: "lightblue"

    MouseArea {
        anchors.fill: parent
        onClicked: {
            loader.sourceComponent = component
            loader2.sourceComponent = component
        }
    }

    Component {
        id: component
        Rectangle {
            width: 80; height: 80
            color: "red"
        }
    }

    Loader { id: loader }
    Loader {
        id: loader2;
        anchors.centerIn: parent
        onLoaded: item.color = "green"
    }
}

由於Component不是繼承自Item,所以使用anchors錨佈局無效,但Loader可以使用。例子中單擊滑鼠時建立了兩個元件,雙擊滑鼠時又把這兩個元件銷燬了,銷燬時需要設定sourceComponent屬性值為undefined

元件分離——

QML檔案本身也可以是一個Component,這樣就與使用它的QML檔案分離開了,這樣做的好處是該Component可以被多個QML檔案使用,程式碼結構也清晰明瞭,此時的Loader用到的就是其source屬性,如下例子:

// comp.qml as a separated Component
import QtQuick 2.2

Item {
    Row {
        spacing: 5
        Rectangle {width: 80; height: 80; color: "red" }
        Rectangle {width: 80; height: 80; color: "yellow" }
        Rectangle {width: 80; height: 80; color: "green" }
    }
}

// main.qml
import QtQuick 2.2

Rectangle {
    width: 360; height: 360
    color: "lightblue"

    MouseArea {
        anchors.fill: parent
        onClicked: {
            loader.source = "comp.qml"
            loader2.source = "comp.qml"
        }
        onDoubleClicked: {
            loader.source = ""
            loader2.source = ""
        }
    }

    Loader { id: loader}
    Loader { id: loader2; y: 100}
}

例子中單擊滑鼠時從外部載入了兩個元件,雙擊滑鼠時又把這兩個元件銷燬了,銷燬時需要設定source屬性值為“”即一個空值。

QML檔案中建立——

先使用Qt.createComponent(url, mode, parent)QML檔案中建立一個元件,必要時可以根據Component.status屬性判斷建立狀態,然後使用Component.createObject()在某個父物件下例項化物件,最後使用destroy()銷燬物件,函式引數可以指定一個時間,單位是毫秒,預設為0,如下例子

import QtQuick 2.2

Rectangle {
    property var object
    property var component

    width: 360; height: 360
    color: "lightblue"

    MouseArea {
        anchors.fill: parent
        onPressed: {
            component = Qt.createComponent("comp.qml")
            if(Component.Ready === component.status) {
                object = component.createObject(parent)
            }
        }
        onReleased: {
            object.destroy(2000)
        }
    }
}

例子中按下滑鼠時從QML檔案中建立了一個元件component並例項化一個物件object,釋放滑鼠時在2000毫秒後物件object銷燬,但元件component還是存在的。

QML字串中建立——

使用Qt.createQmlObject(stringqml, object parent, string filepath)QML字串中建立,第一個引數是要建立物件的QML字串,第二個引數指定要建立物件的父物件,第三個引數用於報告錯誤,例子如下:

import QtQuick 2.2

Rectangle {
    property var object

    width: 360; height: 360
    color: "lightblue"

    MouseArea {
        anchors.fill: parent
        onPressed: object = Qt.createQmlObject('import QtQuick 2.2; Rectangle { color: "red"; width: 100; 	height: 100; anchors.centerIn: parent }', parent, "dynamicSnippet")
        onReleased: object.destroy(1000)
    }
}

如果修改例子中Qt.creatQmlObject()的第一個引數的“color”為“colo”,程式執行時將會報錯,這時第三個引數就派上用場了,且看錯誤提示如下:

Error: Qt.createQmlObject(): failed to create object: 
qrc:///dynamicSnippet:1:33: Cannot assign to non-existent property "colo"

這裡共列舉了動態元件建立與銷燬的四種方法,實際使用過程中可按需選擇。