首页 > 代码库 > QML如何创建动态组件

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
        onl oaded: 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"

这里共列举了动态组件创建与销毁的四种方法,实际使用过程中可按需选择。


QML如何创建动态组件