QML⼊门教程:⼆、QML语法
1、QML 是⼀种声明语⾔,⽤于描述程序界⾯。
2、QML 将⽤户界⾯分解成⼀块块⼩的元素,每⼀元素都由很多组件构成。ubuntu使用入门教程
3、QML 定义了⽤户界⾯元素的外观和⾏为;更复杂的逻辑则可以结合 JavaScript 脚本实现。这有点类似于
HTML 和 JavaScript 的关系,前者⽤来显⽰界⾯,后者⽤来定义⾏为。
4、QML 最简单的元素关系是层次关系。⼦元素处于相对于⽗元素的坐标系统中。也就是说,⼦元素的 x 和 y 的坐标值始终相对于⽗元素。
下⾯以代码为例详细介绍:
// rectangle.qml
import QtQuick 2.0
// 根元素:Rectangle
Rectangle {
// 命名根元素
id: root // 声明属性:<name>: <value>
width: 120; height: 240
color: "#D8D8D8"// 颜⾊属性
// 声明⼀个嵌套元素(根元素的⼦元素)
Image {
id: rocket
x: (parent.width - width)/2; y: 40// 使⽤ parent 引⽤⽗元素
source: 'assets/rocket.png'
}
/
/ 根元素的另⼀个⼦元素
Text {
// 该元素未命名
y: rocket.y + rocket.height + 20// 使⽤ id 引⽤元素
width: root.width // 使⽤ id 引⽤元素
horizontalAlignment: Text.AlignHCenter
text: 'Rocket'
}
}
5、QML ⽂档总要有 import 部分,⽤于指定该⽂档所需要引⼊的模块。通常这是⼀个模块名和版本号,⽐如这⾥的 QtQuick 2.0。当然,我们也可以引⼊⾃⼰的模块或者其他⽂件。
6、QML⽂档的第⼆个部分是 QML 元素。⼀个 QML ⽂档有且只有⼀个根元素,类似 XML⽂档的规定。在我们的例⼦中,这个根元素就是 Rectangle 元素。QML 元素使⽤ {} 包围起来。{} 之中是该元素的属性;属性以键值对 name : value 的形式给出。这⼗分类似与JSON 语法。QML 元素可以有⼀个 id 属性,作为该元素的名字。以后我们可以直接⽤这个名字指代该元素,相当于该元素的指针。需要注意的是,id 属性在整个 QML ⽂档中必须是唯⼀的。QML 元素允许嵌套,⼀个 QML 元素可以没有、可以有⼀个或多个⼦元素。⼦元素可以使⽤parent关键字访问其⽗元素。正如上⾯的例⼦中显⽰的那样,我们可以⽤ id,也可以⽤ parent 关键字访问其他元素。⼀个最佳实践是,将根元素的 id 命名为 root。这样我们就可以很⽅便地访问到根元素。
7、QML ⽂档的注释使⽤//注释内容或者/*注释内容*/。这同 C/C++ 或者 JavaScript 是⼀致的。
Text {
// (1) 标识符
id: thisLabel
// (2) x、y 坐标
x: 24; y: 16
// (3) 绑定
height: 2 * width
// (4) ⾃定义属性
property int times: 24
// (5) 属性别名
property alias anotherTimes: times
// (6) ⽂本和值
text: "Greetings " + times
// (7) 字体属性组
font.family: "Ubuntu"
font.pixelSize: 24
/
/ (8) 附加属性 KeyNavigation
KeyNavigation.tab: otherLabel
// (9) 属性值改变的信号处理回调
onHeightChanged: console.log('height:', height)
// 接收键盘事件需要设置 focus
focus: true
// 根据 focus 值改变颜⾊
color: focus?"red":"black"
}
8、标识符 id ⽤于在 QML ⽂档中引⽤这个元素。id 并不是⼀个字符串,⽽是⼀个特殊的标识符类型,这是 QML 语法的⼀部分。如前⽂所述,id 在⽂档中必须是唯⼀的,并且⼀旦指定,不允许重新设置为另外的元素。因此,id 很像 C++ 的指针。和指针类似,id 也不能以数字开头,具体规则同 C++ 指
针的命名⼀致。id 看起来同其它属性没有什么区别,但是,我们不能使⽤ id 反查出具体的值。例
如,aElement.id 是不允许的。 元素 id 应该在 QML ⽂档中是唯⼀的。实际上,QML 提供了⼀种动态作⽤域(dynamic-scoping)的机制,后加载的⽂档会覆盖掉前⾯加载的⽂档的相同 id。这看起来能够“更改” id 的指向,其意义是构成⼀个 id 的查询链。如果当前⽂档没有到这个 id,那么可以在之前加载的⽂档中到。这很像全局变量。不过,这种代码很难维护,因为这种机制意味着你的代码依赖于⽂档的加载顺序。不幸的是,我们没有办法关闭这种机制。因此,在选⽤ id 时,我们⼀定要注意唯⼀性这个要求,否则很有可能出现⼀些很难调试的问题。
9、属性的值由其类型决定。如果⼀个属性没有给值,则会使⽤属性的默认值。我们可以通过查看⽂档到属性默认值究竟是什么。 属性可以依赖于其它属性,这种⾏为叫作绑定。绑定类似信号槽机制。当所依赖的属性发⽣变化时,绑定到这个属性的属性会得到通知,并且⾃动更新⾃⼰的值。例如上⾯的 height: 2* width。height 依赖于 width属性。当 width改变时,height 会⾃动发⽣变化,将⾃⾝的值更新为width新值的两倍。text 属性也是⼀个绑定的例⼦。注意,int 类型的属性会⾃动转换成字符串;并且在值变化时,绑定依然成⽴。 系统提供的属性肯定是不够的。所以 QML 允许我们⾃定义属性。我们可以使⽤ property关键字声明⼀个⾃定义属性,后⾯是属性类型和属性名,最后是属性值。声明⾃定义属性的
语法是 property <type> <name> : <value>。如果没有默认值,那么将给出系统类型的默认值。
我们也可以声明⼀个默认属性,例如:
// MyLabel.qml
import QtQuick 2.0
Text {
default property var defaultText
text: "Hello, " +
}
在 MyLabel 中,我们声明了⼀个默认属性 defaultText。注意这个属性的类型是 var。这是⼀种通⽤类型,可以保存任何类型的属性值。默认属性的含义在于,如果⼀个⼦元素在⽗元素中,但是没有给⼦元素赋值给⽗元素的任何属性,那么⼦元素属性就成为这个默认属性。利⽤上⾯的 MyLabel,我们可以有如下的代码:
MyLabel {
Text { text: "world" }
}
MyLabel.qml 实际可以直接引⼊到另外的 QML ⽂档,当做⼀个独⽴的元素使⽤。所以,我们可以把 MyLabel 作为根元素。注意MyLabel 的⼦元素 Text 没有赋值给 MyLabel 的任何属性,所以,它将⾃动成为默认属性 defaultText 的值。因此,上⾯的代码其实等价于:
MyLabel {
defaultText:Text { text: "world" }
}
这种默认属性的写法很像嵌套元素。其实嵌套元素正是利⽤这种默认属性实现的。所有可以嵌套元素的元素都有⼀个名为 data 的默认属性。所以这些嵌套的⼦元素都是添加到了 data 属性中。
属性也可以有别名。我们使⽤ alias 关键字声明属性的别名:property alias <name> : <reference>。别名和引⽤类似,只是给⼀个属性另外⼀个名字。C++ 教程⾥⾯经常说,“引⽤即别名”,这⾥就是“别名即引⽤”。这种技术对于导出属性⾮常有⽤。例如,我们希望让⼀个⼦元素的属性外部可⽤,那么就
可以给这个属性⼀个别名,让外部⽂档通过这个别名访问这个属性。别名不需要特别声明属性类型,它使⽤被引⽤属性的类型或者 id。需要注意的是,属性别名在组件完全初始化之后才可⽤。因此,下⾯的代码是⾮法的:
property alias myLabel: label
<: "error" // 错误!此时组件还没有初始化
property alias myLabelText: // 错误!不能为属性别名的属性创建别名
属性也可以分组。分组可以让属性更具结构化。上⾯⽰例中的 font 属性另外⼀种写法是:
font { family: "Ubuntu"; pixelSize: 24 }
原写法为:
font.family: "Ubuntu"
font.pixelSize: 24
有些属性可以附加到元素本⾝,其语法是<Element>.<property>: <value>。 每⼀个属性都可以发出信
号,因⽽都可以关联信号处理函数。这个处理函数将在属性值变化时调⽤。这种值变化的信号槽命名为 on + 属性名 + Changed,其中属性名要⾸字母⼤写。例如上⾯的例⼦
中,height 属性变化时对应的槽函数名字就是 onHeightChanged。
10、QML 和 JavaScript 关系密切,下⾯是简单⽰例:
Text {
id: label
x: 24; y: 24
// ⾃定义属性,表⽰空格按下的次数
property int spacePresses: 0
text: "Space pressed: " + spacePresses + " times"
// (1) ⽂本变化的响应函数,使⽤控制台输出信息
onTextChanged: console.log("text changed to:", text)
// 接收键盘事件,需要设置 focus 属性
focus: true
// (2) 调⽤ JavaScript 函数
increment()
}
// 按下 Esc 键清空⽂本
< = ''
}
// (3) ⼀个 JavaScript 函数
function increment() {
spacePresses = spacePresses + 1
}
}
Text 元素会发出 textChanged 信号。我们使⽤ on + 信号名,信号名⾸字母⼤写的属性表⽰⼀个槽函数。也就是说,当 Text 元素发出textChanged 信号时,onTextChanged 就会被调⽤。类似的,onSpacePressed 属性会在空格键按下时被调⽤。此时,我们调⽤了⼀个JavaScript 函数。另外,当height(⾼度) 改变时会使⽤控制台输出⼀个信息
QML ⽂档中可以定义 JavaScript 函数,语法同普通 JavaScript 函数⼀样。
QML 的绑定机制同 JavaScript 的赋值运算符有⼀定类似。它们都可以将右⾯的值赋值给前⾯。不同之处在于,绑定会在后⾯的值发⽣改变时,重新计算前⾯的值;但是赋值只是⼀次性的。绑定是⼀个协议,并且存在于整个⽣命周期。当⼀个新的绑定⽣效或者使⽤JavaScript 赋值给属性时,绑定的⽣命周期就会结束。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论