QML中的Loader是用来动态地载入一个QML的Component。它可以用来载入一个QML文件(使用它的source属性)。它也可以载入一个Component(使用它的sourceComponent属性)。它适合在需要载入一个Component时才载入它,这样避免资源的浪费。它可以动态地载入按需求在需要的时候创建我们需要的Component。更多阅读,可以参照:http://qt-project.org/doc/qt-4.8/qml-loader.html。
1)动态载入一个Component
我们首先来创建我们一个基本的应用。这里我们使用一个"App with Simple UI"的模版。我们首先创建一个称作为"filearray.js"的javascript文件,如下:
var filearray = [
["images/fall1.jpg", "First image"],
["images/fall2.jpg", "Second image"],
["images/fall3.jpg", "Three image"],
["images/fall4.jpg", "Fourth image"]
];
这里创建了一个二维的数组。为了我们能够在应用中使用。同时,我们在"main.qml"中也创建一个Component。这样它可以在我们的应用中动态地产生。代码如下:
Component {
id: imageText
Rectangle {
id:top
anchors.fill: parent
Image {
id:innerImage
anchors.top: parent.top
anchors.topMargin:30
anchors.horizontalCenter: parent.horizontalCenter
width:parent.width*0.8;
height: parent.height*0.8
source:root.currentImage
}
Text{
id:answer
anchors.top:innerImage.bottom
anchors.topMargin:30
horizontalAlignment: Text.AlignHCenter
width:parent.width;
text:root.currentText
}
}
这个Component非常简单。上面使用了一个Image,下面是一个Text。这两个item的内容是从root控件中的两个property中获得。我们希望这root中的这两个property改变时他们的内容也可以改变。
Page {
id: root;
title: i18n.tr("QML Loader")
property int index: 0
property string currentImage
property string currentText:" "
同时,为了说明问题,我们也设计了一个timer。当这个timer每次timeout时,我们希望我们的loader:
Loader {
id: loader
anchors.fill: parent
anchors.centerIn:parent
}
的"sourceComponent"每次都能发生改变,以使得UI得到变化。这里有趣的是,我们也可以为Loader定义它的大小:
- 如果没有定义Loader的大小的话,Loader将会自动地适配到Component的大小尺寸(当component完成装载以后)
- 如果Loader的大小已经被定义的话,当component完成装载后,component的尺寸将自动被适配到Loader的尺寸
function timeout() {
console.log("root.index" + root.index);
console.log(FileExt.filearray[root.index][0]);
root.currentImage = FileExt.filearray[root.index][0];
root.currentText = FileExt.filearray[root.index][1];
loader.sourceComponent = imageText;
root.index++;
if ( root.index === FileExt.filearray.length) {
root.index = 0;
}
}
Timer {
id: timer
interval: 3000
onTriggered: {
timeout();
}
repeat: true
triggeredOnStart: true
}
运行的效果图如下:
我们可以看到画面中的每三秒改变一次。每一次都是一个新的Component,而不是同一个Component不变,只是其中的属性发生改变。Loader很适用于在不同的场景中装载不同的component,比如在不同的菜单中,装载不同的component,以显示不同的UI。Qt SDK很多的例程就是这样写的!
整个例程的代码在如下地址找到:
bzr branch
lp:~liu-xiao-guo/debiantrial/loaderqml
2)使用Loader载入qml文件
在下面的例程中,我们来完成一个使用Loader来载入qml文件。我们来做一个类似wizard的东西。当第一个页面显示完后,紧接着按下一个按钮,进入下一个页面。我们首先来创建一个简单的"App with Simple UI"的模版应用,然后,修改main.qml文件:
import QtQuick 2.0
import Ubuntu.Components 1.1
import "components"
MainView {
// objectName for functional testing purposes (autopilot-qt5)
objectName: "mainView"
// Note! applicationName needs to match the "name" field of the click manifest
applicationName: "com.ubuntu.developer.liu-xiao-guo.wizard"
//automaticOrientation: true
// Removes the old toolbar and enables new features of the new header.
useDeprecatedToolbar: false
width: units.gu(100)
height: units.gu(75)
Page {
id: root
title: i18n.tr("Wizard")
Loader {
z: 1
id: main
anchors.fill: parent
}
Image {
source: "images/fall1.jpg"
anchors.fill: parent
}
Button {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.rightMargin: 20
text: "Go to Page 1"
onClicked: {
main.source = "Page1.qml"
console.log("Clicked in main")
}
}
Connections {
target:main.item
onHandlerLoader:{
console.log("Something happened!")
}
}
}
}
这里我们定义了一个叫做main的Loader。当我们点击按钮”Go to Page 1"时,我们使用它来装载另外一个页面“Page1.qml"。注意我们在这里设置它的"z" order值为"1”。同时,我们也可以通过如下的Connections来接受来自main Loader的一些signal来做我们所需要的一些处理。
Connections {
target:main.item
onHandlerLoader:{
console.log("Something happened!")
}
}
在我们的Page1.qml文件中,我们设计如下:
import QtQuick 2.0
import Ubuntu.Components 1.1
Rectangle {
id:page1
anchors.fill: parent
signal handlerLoader;
Loader{
z: 2
id:loader
anchors.fill: parent
}
Image {
source: "images/fall2.jpg"
anchors.fill: parent
}
Button {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.rightMargin: 20
text: "Go to Page 2"
onClicked: {
loader.source = "Page2.qml"
handlerLoader();
}
}
}
在这里,我们定义了另外一个Loader, 并且设置它的“z” order值为2,使一个画面得它可以覆盖以前的页面。我们也尝试定义了一个signal "handlerLoader"。这样我们可以使得前一个面可以的得到一个响应。我们可以把我们想要的信号通过这样的方式发送出去,让需要对它感兴趣的代码利用它。
运行我们的程序,结果如下:
代码在如下的地址可以找到:
bzr branch
lp:~liu-xiao-guo/debiantrial/wizard