1、快速入门
基础语法:
a. import声明导入了一个指定的模块版本。一般来说会导入QtQuick2.0来作为初始元素的引用。
b. 使用//可以单行注释,使用/**/可以多行注释,就像C/C++和JavaScript一样。
c. 每一个QML文件都需要一个根元素,就像HTML一样。
d. 一个元素使用它的类型声明,然后使用{}进行包含。
e. 元素拥有属性,他们按照name:value的格式来赋值。
f. 任何在QML文档中的元素都可以使用它们的id进行访问(id是一个任意的标识符)。
g. 元素可以嵌套,这意味着一个父元素可以拥有多个子元素。子元素可以通过访问parent关键字来访问它们的父元素。
基本元素:
元素名称 | 元素描述 |
Item(基础元素对象) | |
Rectangle (矩形框元素) | |
Text(文本元素) | |
Image(图像元素) | |
MouseArea(鼠标区域元素) |
组件:一个组件是一个可以重复使用的元素,QML提供几种不同的方法来创建组件。一个文件就是一个基础组件。
简单的切换:
定位元素:
布局元素:
输入元素:
高级用法:
2、动态元素
动画:
状态与过渡:
在QML中,使用State元素来定义状态,需要与基础元素对象(Item)的states序列属性连接。状态通过它的状态名来鉴别,由组成它的一系列简单的属性来改变元素。默认的状态在初始化元素属性时定义,并命名为“”(一个空的字符串)。
Item {
id: root
states: [
State {
name: "go"
PropertyChanges { ... }
},
State {
name: "stop"
PropertyChanges { ... }
}
]
}
状态的改变由分配一个元素新的状态属性名来完成。
注意:另一种切换属性的方法是使用状态元素的when属性。when属性能够被设置为一个表达式的结果,当结果为true时,状态被使用。
Item {
id: root
states: [
...
]
Button {
id: goButton
...
onClicked: root.state = "go"
}
}
Rectangle {
id: light1
x: 25; y: 15
width: 100; height: width
radius: width/2
color: "black"
}
Rectangle {
id: light2
x: 25; y: 135
width: 100; height: width
radius: width/2
color: "black"
}
state: "stop"
states: [
State {
name: "stop"
PropertyChanges { target: light1; color: "red" }
PropertyChanges { target: light2; color: "black" }
},
State {
name: "go"
PropertyChanges { target: light1; color: "black" }
PropertyChanges { target: light2; color: "green" }
}
]
MouseArea {
anchors.fill: parent
onClicked: parent.state = (parent.state == "stop"? "go" : "stop")
}
过渡:一系列的过渡能够被加入任何元素,一个过渡由状态的改变触发执行。你可以使用属性的from:和to:来定义状态改变的指定过渡。这两个属性就像一个过滤器,当过滤器为true时,过渡生效。也可以使用“”来表示任何状态。例如from:""; to:"*"表示从
任一状态到另一个任一状态的默认值,这意味着过渡用于每个状态的切换。
transitions: [
Transition {
from: "stop"; to: "go"
ColorAnimation { target: light1; properties: "color"; duration: }
ColorAnimation { target: light2; properties: "color"; duration: }
]
高级用法:
3、模型-视图-代理
在QtQuick中,数据通过model-view(模型-视图)分离。对于每个view(视图),每个数据元素的可视化都分给一个代理(delegate)。在QML中,model(模型)与view(视图)都通过delegate(代理)连接起来。
显示在view(视图)中的每项数据,都是通过delegate(代理)来实现可视化。view(视图)的任务是排列这些delegate(代理),每个delegate(代理)将modelitem(模型项)的值显示给用户。
基础模型:
最基本的分离数据与显示的方法是使用Repeater元素。它被用于实例化一组元素项,并且很容易与一个用于填充用户界面的定位器相结合。最基本的实现举例,repeater元素用于实现子元素的标号。每个子元素都拥有一个可以访问的属性index,用于区分不同的子元素。
import QtQuick 2.0
Column {
spacing: 2
Repeater {
model: 10
Rectangle {
width: 100
height: 20
radius: 3
color: "lightBlue"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
Column {
spacing: 2
Repeater {
model: [
"Enterprise", "Colombia", "Challenger", "Discovery", "Endeavour", "Atlantis"
]
Rectangle {
width: 100
height: 20
radius: 3
color: "lightBlue"
Text {
anchors.centerIn: parent
text: index +": "+modelData
}
}
}
}
Column {
spacing: 2
Repeater {
model: ListModel {
ListElement { name: "Mercury"; surfaceColor: "gray" }
ListElement { name: "Venus"; surfaceColor: "yellow" }
ListElement { name: "Earth"; surfaceColor: "blue" }
ListElement { name: "Mars"; surfaceColor: "orange" }
ListElement { name: "Jupiter"; surfaceColor: "orange" }
ListElement { name: "Saturn"; surfaceColor: "yellow" }
ListElement { name: "Uranus"; surfaceColor: "lightBlue" }
ListElement { name: "Neptune"; surfaceColor: "lightBlue" }
}
Rectangle {
width: 100
height: 20
radius: 3
color: "lightBlue"
Text {
anchors.centerIn: parent
text: name
}
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 2
width: 16
height: 16
radius: 8
border.color: "black"
border.width: 1
color: surfaceColor
}
}
}
}
repeater的内容的每个子项实例化时绑定了默认的属性delegate(代理)。
动态视图:
Repeater元素适合有限的静态数据,但是在真正使用时,模型通常更加复杂和庞大,我们需要一个更加智能的解决方案。QtQuick提供了ListView和GridView元素,这两个都是基于Flickable(可滑动)区域的元素,因此用户可以放入更大的数据。
同时,它们限制了同时实例化的代理数量。对于一个大型的模型,这意味着在同一个场景下只会加载有限的元素。
import QtQuick 2.0
Rectangle {
width: 80
height: 300
color: "white"
ListView {
anchors.fill: parent
anchors.margins: 20
clip: true
model: 100
delegate: numberDelegate
spacing: 5
}
Component {
id: numberDelegate
Rectangle {
width: 40
height: 40
color: "lightGreen"
Text {
anchors.centerIn: parent
font.pixelSize: 10
text: index
}
}
}
}
如果模型包含的数据比屏幕上显示的更多,ListView元素只会显示部分的链表内容。然后由于QtQuick的默认行为导致的问题,列表视图不会限制被显示的代理项(delegates)只在限制区域内显示。这意味着代理项可以在列表视图外显示,用户可以看见在列表视图外动态的创建和销毁这些代理项(delegates)。为了防止这个问题,ListView通过设置clip属性为true,来激活裁剪功能。
代理:
当使用模型与视图来自定义用户界面时,代理在创建显示时扮演了大量的角色。在模型中的每个元素通过代理来实现可视化,用户真实可见的是这些代理元素。
每个代理访问到索引号或者绑定的属性,一些是来自数据模型,一些来自视图。来自模型的数据将会通过属性传递到代理。来自视图的数据将会通过属性传递视图中与代理相关的状态信息。
4、画布元素
画布元素(canvas element)的基本思想是使用一个2D对象来渲染路径。这个2D对象包括了必要的绘图函数,画布元素(canvas element)充当绘制画布。2D对象支持画笔,填充,渐变,文本和绘制路径创建命令。
import QtQuick 2.0
Canvas {
id: root
width: 200; height: 200 // canvas size
// handler to override for drawing
onPaint: {
var ctx = getContext("2d") // get context to draw with
// setup the stroke
ctx.lineWidth = 4
ctx.strokeStyle = "blue"
ctx.fillStyle = "steelblue" // setup the fill
ctx.beginPath() // begin a new path to draw
ctx.moveTo(50,50) // top-left start point
ctx.lineTo(150,50) // upper line
ctx.lineTo(150,150) // right line
ctx.lineTo(50,150) // bottom line
ctx.closePath() // left line through path closing
ctx.fill() // fill using fill style
ctx.stroke() // stroke using line width and stroke style
}
}
典型绘制命令调用如下:
1. 装载画笔或者填充模式
2. 创建绘制路径
3. 使用画笔或者填充绘制路径
onPaint: {
var ctx = getContext("2d")
ctx.strokeStyle = "red" // setup the stroke
ctx.beginPath() // create a path
ctx.moveTo(50,50)
ctx.lineTo(150,50)
ctx.stroke() // stroke path
}
便捷的接口(Convenient API):
在绘制矩形时,我们提供了一个便捷的接口,而不需要调用stroke或者fill来完成。
import QtQuick 2.0
Canvas {
id: root
width: 120; height: 120
onPaint: {
var ctx = getContext("2d")
ctx.fillStyle = 'green'
ctx.strokeStyle = "blue"
ctx.lineWidth = 4
ctx.fillRect(20, 20, 80, 80) // draw a filles rectangle
ctx.clearRect(30,30, 60, 60) // cut our an inner rectangle
// stroke a border from top-left to
// inner center of the larger rectangle
ctx.strokeRect(20,20, 40, 40)
}
}
渐变(Gradients)
画布中可以使用颜色填充也可以使用渐变或者图像来填充。
onPaint: {
var ctx = getContext("2d")
var gradient = ctx.createLinearGradient(100,0,100,200)
gradient.addColorStop(0, "blue")
gradient.addColorStop(0.5, "lightsteelblue")
ctx.fillStyle = gradient
ctx.fillRect(50,50,100,100)
}
阴影(Shadows)
2D对象的路径可以使用阴影增强显示效果。阴影是一个区域的轮廓线使用偏移量,颜色和模糊来实现的。所以你需要指定一个阴影颜色(shadowColor),阴影X轴偏移值(shadowOffsetX),阴影Y轴偏移值(shadowOffsetY)和阴影模糊
(shadowBlur)。这些参数的定义都使用2D context来定义。2D context是唯一的绘制操作接口。
阴影也可以用来创建发光的效果。在下面的例子中我们使用白色的光创建了一个“Earth”的文本。在一个黑色的背景上可以有更加好的显示效果。
首先我们绘制黑色背景:
// setup a dark background
ctx.strokeStyle = "#333"
ctx.fillRect(0,0,canvas.width,canvas.height);
然后定义我们的阴影配置:
ctx.shadowColor = "blue";
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
// next line crashes
// ctx.shadowBlur = 10;
最后我们使用加粗的,80像素宽度的Ubuntu字体来绘制“Earth”文本:
ctx.font = 'Bold 80px Ubuntu';
ctx.fillStyle = "#33a9ff";
ctx.fillText("Earth",30,180);
图片(Images)
QML画布支持多种资源的图片绘制。在画布中使用一个图片需要先加载图片资源。
在我们的例子中我们使用Component.onCompleted操作来加载图片。
onPaint: {
var ctx = getContext("2d")
ctx.drawImage('assets/ball.png', 10, 10) // draw an image
// store current context setup
ctx.save()
ctx.strokeStyle = 'red'
// create a triangle as clip region
ctx.beginPath()
ctx.moveTo(10,10)
ctx.lineTo(55,10)
ctx.lineTo(35,55)
ctx.closePath()
// translate coordinate system
ctx.translate(100,0)
ctx.clip() // create clip from triangle path
// draw image with clip applied
ctx.drawImage('assets/ball.png', 10, 10)
// draw stroke around path
ctx.stroke()
// restore previous setup
ctx.restore()
}
Component.onCompleted: {
loadImage("assets/ball.png")
}
转换(Transformation)
画布有多种方式来转换坐标系。这些操作非常类似于QML元素的转换。你可以通过缩放(scale),旋转(rotate),translate(移动)来转换坐标系。与QML元素的转换不同的是,转换原点通常就是画布原点。
import QtQuick 2.0
Canvas {
id: root
width: 240; height: 120
onPaint: {
var ctx = getContext("2d")
ctx.strokeStyle = "blue"
ctx.lineWidth = 4
ctx.beginPath()
ctx.rect(-20, -20, 40, 40)
ctx.translate(120,60)
ctx.stroke()
// draw path now rotated
ctx.strokeStyle = "green"
ctx.rotate(Math.PI/4)
ctx.stroke()
}
}
5、粒子模拟
6、着色器效果
7、多媒体
8、网络
9、存储
10、动态QML
11、javaScript
12、Qt and C++
13、C++扩展QML
14、Other