【QML 快速入门】属性(Properties)
一、对象(Object)
在前面对象类型处已经讲明了什么是对象,这里再重申一下。QML 对象由类型指定,一般与类型同名,名称以大写字母开头,后面跟一对大括号,在括号中包含了对象特性定义,包括 id、属性、信号、信号处理器、方法、附加属性和附加信号处理器等,当然也可以包含子对象。例如,前面代码中 Rectangle 对象中包含了 id、width、color等属性定义和 Image、Text 子对象。 详情请参考官方文档:QML Object Attributes
二、属性(Properties)
属性是对象的特性之一,可以分配一个静态的值或者绑定一个动态表达式,属性和值由一个冒号隔开,使用 “属性 : 值” 语法进行初始化,比如前面代码中width: 640
。属性可以分行写,这样结尾可以不用分号,也可以写在一行,中间使用分号隔开,例如:width: 640; height: 480
。
import QtQuick 2.0
Text {
// (1) identifier
id: thisLabel
// (2) set x- and y-position
x: 24; y: 16
// (3) bind height to 2 * width
height: 2 * width
// (4) custom property
property int times: 24
// (5) property alias
property alias anotherTimes: thisLabel.times
// (6) set text appended by value
text: "Greetings " + times
// (7) font is a grouped property
font.family: "Ubuntu"
font.pixelSize: 24
// (8) KeyNavigation is an attached property
KeyNavigation.tab: otherLabel
// (9) signal handler for property changes
onHeightChanged: console.log('height:', height)
// focus is neeed to receive key events
focus: true
// change color based on focus value
color: focus?"red":"black"
}
让我们来看看不同属性的特点:
- id 是一个非常特殊的属性值,它在一个 QML 文件中被用来引用元素。id 不是一个字符串,而是一个标识符和 QML 语法的一部分。一个 id 在一个 QML 文档中是唯一的,并且不能被设置为其它值,也无法被查询(它的行为更像 C++ 世界里的指针)。
- 一个属性能够设置一个值,这个值依赖于它的类型。如果没有对一个属性赋值,那么它将会被初始化为一个默认值。你可以查看特定的元素的文档来获得这些初始值的信息。
- 一个属性能够依赖一个或多个其它的属性,这种操作称作属性绑定。当它依赖的属性改变时,它的值也会更新。这就像订了一个协议,在这个例子中 height 始终是 width 的两倍。
- 添加自己定义的属性需要使用 property 修饰符,然后跟上类型,名字和可选择的初始化值(property : )。如果没有初始值将会给定一个系统初始值作为初始值。注意如果属性名与已定义的默认属性名不重复,使用 default 关键字你可以将一个属性定义为默认属性。这在你添加子元素时用得着,如果他们是可视化的元素,子元素会自动的添加默认属性的子类型链表(children property list)。
- 另一个重要的声明属性的方法是使用 alias 关键字(property alias : )。alias 关键字允许我们转发一个属性或者转发一个属性对象自身到另一个作用域。我们将在后面定义组件导出内部属性或者引用根级元素 id 会使用到这个技术。一个属性别名不需要类型,它使用引用的属性类型或者对象类型。
- text 属性依赖于自定义的 timers(int 整型数据类型)属性。int 整型数据会自动的转换为 string 字符串类型数据。这样的表达方式本身也是另一种属性绑定的例子,文本结果会在 times 属性每次改变时刷新。
- 一些属性是按组分配的属性。当一个属性需要结构化并且相关的属性需要联系在一起时,我们可以这样使用它。另一个组属性的编码方式是 font{family: "UBuntu"; pixelSize: 24 }。
- 一些属性是元素自身的附加属性。这样做是为了全局的相关元素在应用程序中只出现一次(例如键盘输入)。
- 对于每个元素你都可以提供一个信号操作。这个操作在属性值改变时被调用。例如这里我们完成了当 height(高度)改变时会使用控制台输出一个信息。
警告:
一个元素 id 应该只在当前文档中被引用。QML 提供了动态作用域的机制,后加载的文档会覆盖之前加载文档的元素 id 号,这样就可以引用已加载并且没有被覆盖的元素 id,这有点类似创建全局变量。但不幸的是这样的代码阅读性很差。目前这个还没有办法解决这个问题,所以你使用这个机制的时候最好仔细一些甚至不要使用这种机制。如果你想向文档外提供元素的调用,你可以在根元素上使用属性导出的方式来提供(就是定义属性)。
2.1 属性更改通知
当一个属性更改值时,它会发送一个信号来告知这个更改。要获取这个信号,只需要创建一个信号处理器(signal handler),它使用on<Property>Changed
语法来命名。示例程序如下:
Rectangle {
width: 640; height:480
onWidthChanged: console.debug("Width has changed to:", width)
onHeightChanged: console.debug("height has changed to:", width)
}
Rectangle 元素拥有 width 和 height 属性,且定义了两个信号处理器,无论何时属性被修改了,都会自动调用它们。
2.2 列表属性
列表是包括在方括号内,以逗号分隔的多个元素的集合。示例如下:
Item {
children: [
Image {},
Text {}
]
}
如果列表中只有一个元素,那么可以省略掉方括号:
Item {
children: Text {}
}
其实列表和 ESMAScript 的数组(Array)是类似的,其访问方式也一样:
- 可以用 [value1, value2, ..., valueN] 这种形式给 list 对象赋值。
- length 属性提供了列表内元素的个数。
- 列表内的元素通过数组下标来访。
访问列表的示例程序如下:
Item {
children:{
Text {
text: "textOne"
}
Text {
text: "textTwo"
}
}
Component.onCompleted: {
for (vat i=0; i<children.length; i++)
console.log("text of label", i, ":", children[i].text)
}
}
2.3 分组属性
在某些情况下使用一个 "." 符号或分组符号将相关的属性形成一个逻辑组。有时我们给分组属性赋值是一个个来的,类似于这样:
Text {
font.pixelSize: 18
font.bold: true
}
其实下面这样的写法在形式上更贴合分组的含义:
Text {
font { pixelSize: 18; bold: true; }
}
其实可以这么理解,font 属性的类型本身是一个对象,这个对象又有 pixelSize、bold、italic、underline 等属性。对于类型为对象的属性值,可以使用 "." 操作符展开对象的每一个成员对其赋值,也可以通过分组符号(一对花括号)把要赋值的成员放在一起给它们赋值。
2.4 附加属性
在 QML 语言的语法中,有一个附加属性的概念,这是附加到一个对象上的额外的属性。举个例子,下面的 Item 对象使用了附加属性:
import QtQuick 2.2
Item {
width: 100
height: 100
focus: true
keys.enabled: false
}
你看,Item 对象设置 keys.enabled 为false,Keys 就是 Qt Quick 提供的供 Item 处理按键事件的附加属性。与附加属性相似的概念还有附加信号处理器,我们后面再讲。
参考:
《Qt Quick 核心编程》第3章 QML语言基础