首页 > 代码库 > QML如何创建动态组件
QML如何创建动态组件
QML动态组件指的是按需分配,需要时我们就创建一个自定义组件,也就是所谓的对象延迟实例化,而不是在程序一开始就创建它,不需要时我们就把它销毁以节约内存,而不是传统意义上的隐藏或覆盖。我们可以使用Component与Loader,也可以使用JavaScript的形式来完成。
先来介绍一下Component——
progress属性,加载组件的过程,从0.0到1.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,默认为异步,返回值的属性有status、object、onStatusChanged、forceCompletion(),其中
forceCompletion()函数强制同步创建对象。
再来看一下Loader——
active属性,默认为true,设置成false时将不能加载组件。
asynchronous属性,默认为false,设置成true时异步加载组件。
item属性,只读属性,保存了成功加载的组件。
progress属性,只读属性,从0.0到1.0变化。
source属性,加载的组件是一个独立的QML文件。
sourceComponent属性,在同一个QML文件中加载组件。
status属性,加载组件的状态,其枚举值分别是Loader.Null/Ready/Loading/Error。
loaded()信号,组件成功加载时触发。
object setSource(urlsource, object properties)函数,设置预加载组件路径。
在同一个QML文件中使用Component和Loader——
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如何创建动态组件