ttp://blog.csdn.net/xiangzi_011/article/details/25488137
qml Loader是用来动态加载qml components的,这样就可以在你需要相应的component时才创建它。好处我就不说了。
1.加载方式
Loader可以通过两种方式来加载components,一种是通过source属性来加载一个qml文件(例子1),另一种是通过sourceComponent属性来加载(例子2)。这两种方式都是在鼠标click root后才加载的。
例子1:
import QtQuick 2.2
Rectangle {
id:root
width: 360
height: 360
Loader
{
id:loader
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.source = "Page.qml";
}
}
}
例子2:
import QtQuick 2.2
Rectangle {
id:root
width: 360
height: 360
Loader
{
id:loader
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.sourceComponent = component1
}
}
Component
{
id:component1
Rectangle {
width: 100
height: 62
color: "red"
}
}
}
2. 位置和大小
通过Loader加载的Component的大小和位置,可以通过Loader来进行设置,如果不设置,则Component会使用默认的大小和位置。
直接看代码:
Rectangle {
id:root
width: 200
height: 200
Loader {
anchors.fill: parent //rect会充满root
sourceComponent: rect
}
Component {
id: rect
Rectangle {
width: 50
height: 50
color: "red"
}
}
}
Rectangle {
id:root
width: 200
height: 200
Loader {
anchors.centerIn: parent //rect会处于root的中心
sourceComponent: rect
}
Component {
id: rect
Rectangle {
width: 50
height: 50
color: "red"
}
}
}
3. 接收Loader加载的Component的信号
Loader加载的Component发送的任何信号都可以通过Connections方式来处理。target代表发送信号者,这里通过Loader的item属性来获取加载的Component对象,onMessage是对应message信号的处理方法。其实就是一个信号绑定过程。
Rectangle {
id:root
width: 200
height: 200
Loader {
id: myLoader
sourceComponent: rect
}
Connections {
target: myLoader.item //代表的是rect,但是这里不能直接使用rect,通过Loader加载的对象只能通过item属性进行访问
onMessage: console.log(msg)
}
Component {
id: rect
Rectangle {
signal message(string msg) //声明信号
width: 50
height: 50
color: "red"
MouseArea
{
anchors.fill: parent
onClicked:
{
message("rect clicked!");//发送message信号
}
}
}
}
}
4. Component的销毁
当source或是sourceComponent属性发生变化时,之前加载的项都会被销毁,将source设置成空字符串或是将sourceComponent属性设置成null可以销毁当前已经加载的项,释放Loder所占用的资源。下面例子点击root时会进行判断,如果loader.sourceComponent为null,就设置成component1,component创建,log里输出"component1onCompleted",如果不为空,就设置为null,就会销毁component,log里输出"component1 onDestruction"。可见component1对象已经被销毁。
Rectangle {
id:root
width: 360
height: 360
Loader
{
id:loader
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.sourceComponent = (loader.sourceComponent==null)? component1:null
}
}
Component
{
id:component1
Rectangle {
width: 100
height: 62
color: "red"
Component.onCompleted:
{
console.log("component1 onCompleted");
}
Component.onDestruction:
{
console.log("component1 onDestruction");
}
}
}
}
5. 从QtQuick 2.0以后,Loader可以加载任何qml中的类型,包括QtObject,Timer等非可视化的元素。下面例子中就是实现在一个Text中显示当前的时间。
Rectangle {
id:root
width: 200
height: 200
Text {
id: text
anchors.fill: parent
color: "red"
text: myLoader.item.displayTime //通过myLoader.item访问Timer的displayTime属性
}
Loader {
id: myLoader
sourceComponent:
Component {
id:noVisualComponent
Timer {
property string displayTime:Date().toString()
interval: 500; running: true; repeat: true
onTriggered: displayTime = Date().toString()
}
}
}
}
6. 焦点和键盘事件
Loader是一个焦点区域,如果想让Loader的子item获得活动的焦点,必须将Loader的focus属性设置为真。同时如果Loader的子item将accepted属性设置为true后,Loader所在的Item将捕捉不到相应的事件。
下面的例子就是root item鼠标按下前可以捕获按键事件,当鼠标按下后,myComponent被创建,注意Loader和Loader的子item的focus属性都要设置为true。将myComponent中event.accepted = true;改为event.accepted = false; 那么键盘事件会继续传播到root item。
import QtQuick 2.0
Rectangle {
width: 200; height: 200
Loader {
id: loader
focus: true
}
MouseArea {
anchors.fill: parent
onClicked: loader.sourceComponent = myComponent;
}
Keys.onPressed: {
console.log("root Item captured:", event.text);
}
Component
{
id:myComponent
Item {
Item {
focus: true
Keys.onPressed: {
console.log("Loaded item captured:", event.text);
event.accepted = true;
}
}
}
}
}
7. 在view delegate中使用Loader
我们可以在ListView的delegate中使用Loader动态的创建Component,来优化ListView的加载性能。这里需要注意:delegateComponent上下文中的 context 属性的访问限制问题。直接上官网给的代码。
Item { width: 400 height: 400 Component { id: myComponent Text { text: index } //Text无法访问到delegateComponent中的index属性 } ListView { anchors.fill: parent model: 5 delegate: Component { id: delegateComponent Loader { sourceComponent: myComponent } } } }
如果想解决这个问题,大概有三种方式。
1)可以将delegateComponent改为inline形式
delegate: Component { Loader { sourceComponent: Component { Text { text: index } //这里Text可以直接访问index属性了 } } }
2)将delegateComponent实现到一个单独的qml文件中
delegate: Component { Loader { source: "MyComponent.qml" } }
myComponent.qml中的Text元素中可以直接访问index属性
3)给Loader增加自定义属性,
Item { width: 400 height: 400 Component { id: myComponent Text { text: modelIndex } //这里可以正常访问Loader自定义属性了 } ListView { anchors.fill: parent model: 5 delegate: Component { Loader { property int modelIndex: index //自定义属性,绑定index sourceComponent: myComponent } } } }