导语
前面两篇我们已经成功创建了Qt Quick项目,并搭载好了Android开发环境。俗话说万事开头难,大家可能没感觉到自己已经把最难的地方完成了。接下来就要正式开始探索炫酷的Qt Quick世界了,不过,在这之前,还是需要学习一下Qt Quick世界的相关规则,不然,后面遇到各种问题,会严重影响我们探索的效率和心情!
Qt Quick世界的规则,也可以说是QML语法。说到规则,大家一定会感到很枯燥,一定要学吗?如果哪位同学现在已经考过了驾照,那些条款制度现在还能记住几条?其实,我们不需要完全记住哪条交通规则要扣多少分罚多少款,这个可以到需要的时候再去查,我们只要记住哪些行为是不对的,这就够了。学习语言语法也类似,不要一开始就把什么都死记背过,这个作用不大,能记住有哪些规则或概念就够了,到真正碰到的时候可以再回头来学。等后面用的多了,自然就熟记于心了!
下面,我们开始,尽量让大家不会太枯燥!
语法基础
我们新建空的Qt Quick项目helloqml,下面更改一下自动生成的main.qml文件:
// 下面是导入语句
import QtQuick 2.9
import QtQuick.Window 2.2
/* QML文档可以看做是一个QML对象树,这里创建了Window根对象
和它的子对象Text */
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Text {
id: text1
text: qsTr("hello QML!")
}
}
1. 导入语句
类似于C++中的 include,在QMl中使用 import 语句导入模块,模块中包含了各种QML类型。QtQuick 模块为创建图形用户界面提供了最基本的类型,比如代码中使用的Text类型就包含在 QtQuick 模块中,QML文档中首先要导入该模块。这里我们导入了 QtQuick 2.9,其实在Qt 5.12中最新的QtQuick模块版本是2.12,使用2.9只是为了向下兼容,如果这里直接使用 QtQuick 2.12,那么使用低于 Qt 5.12 的 Qt 版本编译该源码会报错。关于 QtQuick 模块会在后面的教程中详细讲解。
因为代码中使用了 Window 类型,所以这里还导入了 QtQuick.Window 模块。Window类型可以为 Qt Quick 场景创建一个顶级窗口,所以它一般作为根对象,在其中可以创建其他QML对象。
2. QML类型(QML Types)
QML的类型系统包含了基本类型、 QML 对象类型和 JavaScript 类型,这些类型组成了整个QML文档。
在QML中将指向简单数据的类型称为基本类型,比如 int 或 string 等。基本类型的概念是相对于QML对象类型而言的,QML 对象类型可以包含属性、信号和函数等,但基本类型不能作为对象,比如 int {} 是不允许的。在QML中原生支持的基本类型如下图所示。
QML模块也可以提供基本类型,例如 date、point、rect、size 等。详细内容大家可以在帮助中索引 QML Basic Types
关键字。
- QML对象类型(QML Object Types)
QML对象类型就是可以实例化QML对象的类型。从语法上面来说,QML对象类型可以通过类型名称{对象特性}
的格式来定义一个对象。例如,代码中 Window 和 Text 都是对象类型。当对象类型
被实例化以后,就被叫做该对象类型的对象
,例如 Text 对象类型在代码中被实例化为了 Text 类型的对象 Text,之所以这两个概念容易被混淆,是因为它们是同名的。只需要记住对象类型后面添加 {} 后就被称为对象
,大家也可以类比C++中的类与实例化。
QML支持JavaScript对象和数组,可以通过var
类型创建并存储任何标准的JavaScript类型。下面是一个例子:
import QtQuick 2.0
Item {
property var theArray: []
property var theDate: new Date()
Component.onCompleted: {
for (var i = 0; i < 10; i++)
theArray.push("Item " + i)
console.log("There are", theArray.length, "items in the array")
console.log("The time is", theDate.toUTCString())
}
}
3. 对象
在前面对象类型处已经讲明了什么是对象,这里再重申一下。QML对象由类型指定,一般与类型同名,名称以大写字母开头,后面跟一对大括号,在括号中包含了对象特性(QML Object Attributes)定义,包括 id、属性、信号、信号处理器、方法、附加属性和附加信号处理器等,当然也可以包含子对象。例如,前面代码中 Window 对象中包含了visible、width、height、title等属性定义和 Text 子对象。
4. 属性(Property)
属性是对象的特性之一,可以分配一个静态的值或者绑定一个动态表达式,属性和值由一个冒号隔开,使用“属性 : 值”语法进行初始化,比如前面代码中width: 640
。属性可以分行写,这样结尾可以不用分号,也可以写在一行,中间使用分号隔开,例如:width: 640 ; height: 480
。可以在任意对象类型的帮助文档中查看该类型的所有属性。
一个对象一般都会在开始指定一个id,可以通过它在其他对象中识别并引用该对象,id 特性是QML语言本身提供的,不能被QML对象类型进行重定义或者重写。id 值必须使用小写字母或者下划线开头,并且不能使用字母、数字和下划线以外的字符,其值在一个组件的作用域中必须是唯一的。
id 看起来像是一个属性,但 id 特性并不是一个属性。例如前面代码中Text 对象的 id 为 text1,所以可以在其他对象中通过 text1.text
来获取 Text 对象中的 text 属性的值, 但无法通过text1.id
来获取 id 的值。
5. 注释
QML中的注释与C++相似,单行注释使用 “ // ” 开始,直到行末结束;多行注释使用 “ / ” 开始,以 “ / ” 结尾。
更进一步
编译运行程序,可以看到hello QML!
文本显示在窗口左上角。下面更改 Text 对象定义代码如下:
Text {
id: text1
text: qsTr("hello QML!")
anchors.centerIn: parent
}
现在再次编译运行程序,可以看到文本显示到了界面中间。接下来在 Window 根对象中,Text 对象定义的下面继续添加一个 Rectangle 对象定义:
Rectangle {
id: colorRect
width: 20 * 2
height: width
radius: 20
color: "green"
anchors.left: text1.right
anchors.leftMargin: 10
anchors.verticalCenter: text1.verticalCenter
MouseArea {
anchors.fill: parent
onClicked: {
console.debug("colorRect: ", parent.color)
}
}
}
Rectangle 也是 QtQuick 模块中一个很常用的对象类型,使用它可以定义一个矩形,这里设置了矩形的宽、高为40,半径radius为20,颜色为绿色,它最终显示效果是一个绿色圆形。运行程序,效果如下图所示。
1. 锚布局
前面使用的 anchors 翻译过来就是锚,使用它可以进行简单的布局,当然这只是QML布局中的一种方法,不过很常用。anchors可以在一个部件的上、下、左、右、水平居中、垂直居中、中心等位置进行锚定,如下图所示。
比如Text 对象中 anchors.centerIn: parent
就是将 Text 对象锚定在了其父对象也就是 Window 的中心。在 Rectangle 对象中,我们使用anchors.left: text1.right
将绿色圆形的左侧与文本的右侧进行锚定,效果就是绿色圆形紧挨文本右侧放置;anchors.leftMargin: 10
表明绿色圆形左侧的边距为10;anchors.verticalCenter: text1.verticalCenter
表明绿色圆形的垂直居中位置锚定到文本的垂直居中位置,效果就是绿色圆形与文本在同一行上,且中心线对其。
2. JavaScript表达式和属性绑定
在Rectangle对象中width属性的值使用了表达式 width: 20 * 2
。在表达式中也可以包含其他对象或属性的引用,例如,height: width
,这也被称作属性绑定,当 width 的值改变时,height 属性的值会跟随变化。
3.进行交互
在QML中一个很常见的设置交互的方式是使用MouseArea,MouseArea本身是不可见的,但是它可以为一些可见内容提供鼠标交互,比如这里,MouseArea对象中 anchors.fill: parent
表明让MouseArea填充整个父对象,这里就是绿色圆形,所以我们可以使用鼠标点击绿色圆形的任何部位来进行交互。当鼠标点击后,就可以在MouseArea中使用 onClicked:{}
来执行想要进行的操作。
4.调试输出
在QML中一般使用console将需要的信息输出到控制台,可用的有console.log, console.debug, console.info, console.warn 和 console.error,比如这里使用了console.debug("colorRect: ", parent.color)
,可以顺序输出参数中的内容,可以是字符串,也可以是对象属性引用。
结语
虽然这一篇是最基础的语法,但是依然包含了众多新的术语、概念、名词,对于新的东西,唯有多用多尝试才能快速掌握。下一篇咱们继续对程序进行扩展,会涉及更多新的内容。