2014年12月12日 16:17:39
阅读数:5288
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
-
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"
这里共列举了动态组件创建与销毁的四种方法,实际使用过程中可按需选择。