QML类型——Component
正文
Component是封装好的,定义明确接口的QML类型,可以重用。
组件通常是由组件文件(即.qml文件)定义。Component类型实质上允许在QML文件中内联定义QML组件,而不是将其定义为单独的QML文件。
应用场景:
1.有重用性且比较小的组件。
2.从逻辑上来看属于某个QML文档的组件。
例如,下面是多个Loader对象加载的组件:
import QtQuick 2.0
Item {
width: 100; height: 100
Component {
id: redSquare
Rectangle {
color: "red"
width: 10
height: 10
}
}
Loader { sourceComponent: redSquare }
Loader { sourceComponent: redSquare; x: 20 }
}
请注意,虽然Rectangle本身会自动呈现展示,但上述矩形并非如此,因为它是内联组件。该组件将QML类型封装起来,就好像它们是在一个独立的QML文档中定义一样,并且直到请求时才会被加载(用Loader对象加载)。由于Component不是从Item派生的,因此无法将任何内容锚定到它。
定义一个内联组件就类似于定义一个QML文档。QML文档只有一个父项,它定义了该组件的行为和属性,并且不能在父项之外定义属性或行为。同样,Component也只能定义一个父项(上例中的Rectangle),并且不能在父项外定义任何数据,但id除外(上例中的redSquare)。
Component类型通常用于为视图(view)提供图形组件。例如,ListView::delegate属性就需要一个Component来指定如何呈现列表的每一项。
Component还可以使用Qt.createComponent()动态创建对象。
创建上下文
组件的创建上下文与申明该组件的上下文相对应。当组件由ListView或Loader之类的对象实例化时,此上下文用作父上下文(创建上下文层次结构)。
在以下示例中,comp1是在MyItem.qml的父上下文中创建的,从该组件实例化的任何对象都可以访问该上下文中的id和属性,例如internalSettings.color。当comp1在另一个上下文(如下面的main.qml中)用作ListView委托时,它将继续有权访问其创建上下文的属性(否则它将对外部用户私有)。
MyItem.qml
Item {
property Component mycomponent: comp1
QtObject {
id: internalSettings
property color color: "green"
}
Component {
id: comp1
Rectangle { color: internalSettings.color; width: 400; height: 50 }
}
}
main.qml
ListView {
width: 400; height: 400
model: 5
delegate: myItem.mycomponent //will create green Rectangles
MyItem { id: myItem }
}
重要的是,创建上下文的生存期要比任何创建的对象都要长。详细信息参考维护动态创建的对象。
属性
- progress: real
获取当前加载组件的进度。从0.0(未加载)到1.0(完成)。
- status: enumeration
当前加载组件的状态。
枚举值:
Component.Null-该组件无可用数据
Component.Ready-组件已加载,可用于创建实例。
Component.Loading-当前正在加载组件
Component.Error-加载组件时发生错误。调用errorString()将提供所有错误描述。
- url: url
组件url,用于构造组件的url。
信号
- completed()
对象实例化完成时发送该信号。一旦建立了完整的QML环境,就可以在启动时用来执行脚本代码。
可以在任何对象上声明onCompleted信号处理程序。运行处理程序的顺序是不确定的。
Rectangle {
Component.onCompleted: console.log("Completed Running!")
Rectangle {
Component.onCompleted: console.log("Nested Completed Running!")
}
}
- destruction()
当对象开始销魂时发送信号。此信号可用于撤销响应completed()信号或应用程序中其他命令性代码完成的工作。
可以在任何对象上声明onDestruction信号处理程序。运行处理程序的顺序是不确定的。
Rectangle {
Component.onDestruction: console.log("Destruction Beginning!")
Rectangle {
Component.onDestruction: console.log("Nested Destruction Beginning!")
}
}
方法
- object createObject(parent,object properties)
创建并返回此组件的对象实例,该实例将具有给定的parent和properties。properties参数是可选的。如果对象创建失败,则返回null。
在和创建组件相同的上下文中创建对象,在QML中调用未创建的组件时,此函数将始终返回null。
如果要创建对象但不设置父对象,则需要给parent设置null。如果要显示返回的对象,则在创建时必须提供有效的parent对象,或者给返回的对象设置parent属性,否则该对象将不可见。
如果未给createObject()提供parent对象,则必须保留对返回对象的引用,使它不会被垃圾收集器破坏。无论是否随后设置了Item::parent,这都是正确的,因为设置了Item::parent不会更改对象所有权,仅图形的parent被更改。
从QtQuick1.1开始,此方法接受properties参数可选,该参数指定所创建对象的初始属性。在定义了很多属性值的情况下,设置初始属性值更为有效。并且还允许在创建对象之前设置属性绑定(使用Qt.binding)。
例如下面的代码创建一个对象,其x和y初始值分别为100和100:
var component = Qt.createComponent("Button.qml");
if (component.status == Component.Ready)
component.createObject(parent, {x: 100, y: 100});
使用destroy()方法可以删除动态创建的实例,请参考从JavaScript动态创建QML对象。
- string errorString()
返回所有错误的描述。
该字符串包括每个错误的文件、位置和描述。如果存在多个错误,则用换行符分隔。
如果没有错误,则返回一个空字符串。
- object incubateObject(parent, object properties, enumeration mode)
为该组件的实例创建一个孵化器(参考QQmlIncubator)。孵化器允许使用应用程序空闲事件异步创建组件,并且不会导致UI阻塞。
parent参数指定创建的实例的parent。省略参数或传递null,将创建一个没有parent的对象,在这种情况下,必须保留对创建的对象的引用,以避免垃圾回收器释放它。
properties参数指定初始化属性值,在创建对象时对其设置。
mode参数可以是Qt.Synchronous或Qt.Asynchronous,控制实例是同步还是异步创建。默认为Qt.Asynchronous(异步)。在某些情况下,即使指定了Qt.Synchronous,孵化器也可能异步创建对象,例如调用incubateObject()的组件本身是异步创建的。
这三个参数都是可选的。
如果成功,则返回创建该组件的孵化器对象,否则返回null。
孵化器对象具有以下特效:
1.status - 孵化器的状态,有效值:Component.Ready,Component.Loading和Component.Error。
2.object - 创建的对象示例。只有在孵化器状态为Ready时可用。
3.onStatusChanged - 状态更改时响应的函数,status参数返回新状态。
4.forceCompletion() - 强制同步创建所有在孵化器中的对象。调用返回后,孵化器将不会处于Loading状态。
以下示例演示了如何使用孵化器:
var component = Qt.createComponent("Button.qml");
var incubator = component.incubateObject(parent, { x: 10, y: 10 });
if (incubator.status != Component.Ready) {
incubator.onStatusChanged = function(status) {
if (status == Component.Ready) {
print ("Object", incubator.object, "is now ready!");
}
}
} else {
print ("Object", incubator.object, "is ready immediately!");
}