如官方介绍,QML是一种描述性语言,其类似于CSS的语言,同时又支持javascript。本节我们将开始介绍QML的语法。
QML中的import
在前一节的QML代码中,开始的第一行有一句”inport QtQuick 2.0”。说到这个import关键字,其作用就相当于C/C++中的#include预编译头,它可是我们进行模块复用的工具。不过这个import又稍微有点名堂,一下是它的基本使用方法
import 模块名 版本号 [别名]
模块名是一个可以被导入组件,其可以是系统的模块(比如前一节的QtQuick)和自定义模块,可复用模块的路径等,而可复用的组件不仅是QML文件,一个js文件同样是可以被当做一个组件复用的。
版本号指定的形式为[主版本号.副版本号],如果模块名处是一个路径而不是模块名,版本号可省略
l 别名是一个可以选择的选项,其作用就类似与C++中的namespace。如果指定了别名,则就必须通过别名来访问模块里的成员,不然模块将变为一个全局模块。如果你担心自定义模块可能和别的模块出现命名冲突,建议加上别名这个作用域限制,这个和在C++中我们不推介直接使用”using namespace std”是一个道理,但是本次介绍为了方便默认使用的都是全局作用域。
关于import的进一步用法大家可以参考Qt的帮助手册,此处不再多说。
QML中的对象
对象属性
属性是描述对象特征的重要内容,在之前的Text对象中,我们指定了其text的值才出现了”Hello World”的效果,因此可以知道属性将影响对象的表现,这点和C++中类的属性的是相似的。另外,所有对象中都有一个特殊的属性id,这个属性相当于一个变量名,是一个元素的标识符(可选用),不过id这个属性也只局限在当前qml文件里,此外id必须是小写字母开头的。在同一个qml文件里,我们可以通过id来访问对应对象内部属性、内嵌方法等等。
除了对象内部系统定义的属性外,我们当然也可以声明自定义属性,自定义属性可应使用property关键字,按照以下格式:
[readonly] property <typename> <name> [:defaltvalue]
其中,typename可以是基本数据类型(bool、int、string、real、variant等),可以是已存在的组件,还可以是类似javascript中的var,或者还能是你在C++中自定义的。总之类型很多,大家可以参考手册了解具体可以是哪些类型。另外请注意readonly关键字,如果一个属性被声明为readonly,则在第一次使用这个对象时该属性必须被初始化切之后就不能被改变,同时这个属性也是不可被绑定的。
当然,你也可以通过关联一个已有的属性来声明一个新的属性,格式如下:
property alias <name> : <被关联的属性>
属性关联有一个好处,它可以帮我们去访问到一个组件内部内嵌对象的属性,这在qml文件间的对象访问十分有用。
属性的具体例子我将在本节最后给大家演示。
对象方法
在QML中,声明一个对象的方法不需要太多严格的限制,这不同于C++中严谨的定义。在QML中声明一个方法就和在javascript中写一个函数一样简单,你可以在一个对象里通过以下格式声明一个方法
function <funcname>([arg]...){
//函数体
}
在函数体内,你可以根据需要写出相应的逻辑即可。
信号/槽
同C++/Qt一样,在QML中同样存在信号/槽机制。在一个对象内部,我们可以通过signal关键字来声明一个信号,形式如下
signal <signalName>[([<type> <parameter name>[, ...]])]
声明信号后,我们可以通过像调用普通方法的形式去产生信号,而相对应的槽函数将以如下格式去声明
on<signalname>:{//函数体}
如果信号和槽在同一个对象或者同一个组件内时(比如复用情况下),一般当信号触发时槽函数将会自动调用,不必像C++/Qt中需要用connect函数去显示连接。当然,如果信号需要在两个对象之间传递,我们还有一个功能类似于connect函数的Connections对象,它可以为我们建立两个对象之间的连接,使用方法如下:
Object1{
id:sender
signal mysignal()
}
Objcet2{
Connections{
target:sender
onMysignal:{//函数体}
}
}
说到这里,大家想必也注意到了,在QML中的槽和C++/Qt中的槽貌似有点区别。的确,QML中的槽有点像一个对象的属性(比如用冒号进行某个函数体关联),并且槽是存在一个类型明确的函数参数的(这个参数来自于信号的参数),相比之下QML对象的方法是一个javascript函数。
除了上述的显示声明信号槽外,QML对象中还存在内置信号槽,一般这个信号槽会在对象内属性值变更时被自动触发,对应的槽名称有如下格式:
on<属性名>Changed:{//函数体}
这种内置信号槽的好处可以帮我们轻易的监视对象内部属性的变动,从而做出相对应的逻辑。对于我们自定义的属性,同样是适用的。
QML中对象与对象之间的关系
在QML中,对象与对象也有着类似于C++中类的继承与组合的关系。譬如
Object{
id:root
Child1{
id:child1
}
Child2{
id:child2
}
}
这里的我们以id来指代每一个具体对象。在root中,有child1和child2两个对象,这两个对象分别和root组成了类似继承的形式,因此child1或者child2将继承来自root的某些性质(比如坐标系统),当需要访问root对象时,可以通过之前所说的id或者一个新的关键字parent来进行。而child1和child2作为兄弟对象,他们之间可通过id来相互访问。
另外需要注意的一个问题是,在QML中,必须保证对象树中只有一个根。如上的代码里如果不存在Object这个最外层或者最顶层对象,将会报错。
QML基本对象类型
Item
Item是所有可视化元素的基础,尽管它什么都不绘制,但他确包含了所有可视化元素的共性,如下是直接搬运QmlBook内关于其共性的内容
Group | Properties |
Geometry | x and y to define the top-left position, width and height for the expand of the element and also the z stacking order to lift elements up or down from their natural ordering |
Layout Handling | anchors (left, right, top, bottom, vertical and horizontal center) to position elements relative to other elements with their margins |
Key Handling | attached Key and KeyNavigation properties to control key handling and the input focus property to enable key handling in the first place |
Transformation | scale and rotate transformation and the generic transform property list for x,y,z transformation and their transform Origin point |
Visual | opacity to control transparency, visible to show/hide elements, clip to restrain paint operations to the element boundary and smooth to enhance the rendering quality |
State Definition | states list property with the supported list of states and the current state property as also the transitions list property to animate state changes. |
Rectangle
Rectangle是Item的一个扩展,它为Item增加了颜色表现的定义,比如背景色、渐变色、边属性等,另外它还有一个radius属性,你可以用它来画一个圆角的矩形,甚至是一个圆形
Item{
Rectangle{
anchors.horizontalCenter: parent.horizontalCenter
width:100
height:100
color: "lightblue" //此处为背景色
border.color: "black"
border.width:2
radius: 6
}
Rectangle{
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width:100
height:100
color: "lightblue"
border.color: "black"
border.width:2
radius: 50
}
}
这样一来,就有点类似我们在C++/Qt里通过QPainter对象在一个QWidget对象上绘图,是不是觉得熟悉和相似呢?只不过通过QML进行绘图,一切都更加简单与直观。
Text
Text可以用来展示文字,功能有点类似QLabel,并且它还可以对文字的属性进行设置,比如字体大小、字体类型、文字对齐方式等等。
import QtQuick 2.0
Text{
text:"hello world"
font.bold: true
font.pixelSize: 20
color: "red" //此处为字体颜色
horizontalAlignment: Text.AlignHCenter
}
(关于颜色支持大家可以参考http://www.w3.org/TR/SVG/types.html#ColorKeywords)
Image
Image可以用来显示图片,支持的图片类型请各位参考文档。通过给source属性指定图片位置,由于source为url类型,所以既可以指定本地路径,也可以指定网络路径。同时,Image还有fillMode一个属性用来指定图片的呈现方式,具体数值也请参考文档吧。另外需要说明一个叫做clip的属性,这个属性指定了图片可视范围以外的部分是否会被绘制。
QML可复用组件(Component)
Component是一种可复用的组件。QML中,我们可以在当前文件中以Component关键字来创建一个组件(可以通过id进行调用),也可创建一个基于文件的组件,即我们可以把那些我们认为可以多次复用的代码写到一个文件里(比如一个Button),这样我们便可以通过之前的import将该文件导入作为一个新组件使用,举例如下:
//Button.qml
import QtQuick 2.0
Item{
id:root
width: 15
height: 20
property alias text: buttonText.text
signal clicked
MouseArea{
anchors.fill: parent
onClicked: root.clicked()
}
Text{
id:buttonText
anchors.fill: parent
text:""
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
//main.qml
//如果main.qml和Button.qml在同一路径,下面这句不是必须的
import “/<文件所在路径(不含文件本身)>” as MyComponent
MyComponent{
id :root
onClick: text=”Clicked!”
}
QML Transformation简介
Transformation能够对对象的相关位置信息、尺寸信息进行运算。在QML中,Item是可以被移动、旋转和缩放的。
在位置方面,我们有x、y、z三个属性,他们的作用和QWidget里的是一致的。只不过如果我们的代码里只有一个对象的话,这个属性貌似就不起什么作用了。
在旋转方面用rotation属性来设置,缩放方面用scale来设置,而这两者都需要一个中心点来支持(transformOrigin属性控制,默认为图形的几何中心)
QML位置管理元素
位置管理这方面我们可以和C+/Qt中的布局管理器进行类比。在C++/Qt中,我们有水平布局(QHBoxLayout)、垂直布局(QVBoxLayout)、栅栏布局(QGridBoxLayout)等,在QML里,我们也有相应的Item的子项进行如上操作,比如负责水平排列的Row,负责垂直排列的Column以及负责栅栏排列的Grid等。他们会将其子对象按照加入的顺序进行一定的布局。
Row {
spacing:5
Rectangle {
width: 20
height: 20
color: "red"
}
Rectangle {
width: 20
height: 20
color: "red"
}
}
Column {
spacing:5
Rectangle {
width: 20
height: 20
color: "red"
}
Rectangle {
width: 20
height: 20
color: "red"
}
}
Grid {
spacing:5
columns: 2
rows:2
Rectangle {
width: 20
height: 20
color: "red"
}
Rectangle {
width: 20
height: 20
color: "red"
}
Rectangle {
width: 20
height: 20
color: "red"
}
Rectangle {
width: 20
height: 20
color: "red"
}
}
其他的位置管理相关元素各位可以参考帮助手册,这里就不在举例。
QML布局管理
QML中提供了一种全新的布局管理器,通过anchors.*(*如下图标注)进行操作。
通过这样一套机制,我们可以很方便的将两个Item的子项进行布局管理从而达到我们期望的效果。比如下图这种形式
Item{
Rectangle{
id:rec1
width:50
height: 50
color:"red"
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle{
id:rec2
width: 50
height: 50
color :"red"
anchors.left: rec1.right
anchors.top:rec1.bottom
}
}
QML常见可交互元素
MouseArea
虽然MouseArea也是来自Item,但它却是一个不可见的元素。尽管不可见,但它却能够和其他可见的元素紧密配合,用来捕获鼠标的操作。在MouseArea中,比较常见的就其onClicked;{//函数体}槽的使用,用来响应用户按下鼠标左键的操作。
Rectangle{
width: 100
height: 100
color:"red"
MouseArea{
anchors.fill: parent
onClicked: color= "black"
}
}
这段代码会在鼠标按下去后使得原来的背景由红变黑。
除了onClicked槽的使用外,MouseArea还可以用来铺货鼠标hover事件、drag时间等等,这个重要的交互元素将会贯穿今后的学习实例中。关于其进一步详细文档,请见Qt帮助文档。
TextInput
TextInput有点类似与C++/Qt中的QLineEdit,使用方式也类似。
TextEdit
TextEdit类似于C++/Qt中的QTextEdit,使用方式类似
FocusScope
FocusScope一般体现在子元素的focus属性上,当获取焦点时此属性将变为真。
Keys
Key是一个特殊的属性。处理这个属性的方式有点类似于我们在C++/Qt中重写QWidget的keyPressEvent方法。正好这里也有一个onKeyPress的槽,在这里我们可以通过event.key来获取键盘上按下的按键,从而做出对应的逻辑。
下一节我们将开始讲解QML中的动画元素以及如何使用动画。