QML对象属性
每个QML对象类型都有一些属性。当创建对象类型的实例时,这些属性就会被自动创建出来。您甚至可以定义一些自己的属性。除枚举属性外,所有属性都以小写字母或下划线开头,并且不能包含字母,数字和下划线以外的字符。
id属性
每个QML对象类型有且仅有一个id
属性,它由QML语言默认提供,用于标识和引用该对象。
import QtQuick Column { width: 200; height: 200 TextInput { id: myTextInput; text: "Hello World" } Text { text: myTextInput.text } }
上面的代码中,定义了TextInput
对象的id
属性值为"myTextInput"。这样就可以在Text
对象里通过"myTextInput"来引用TextInput
对象的属性值。
property
属性
property
属性是用于分配静态值或绑定到动态表达式的对象属性。在QML中定义property
属性语法如下:
[default] [required] [readonly] property <propertyType> <propertyName>
其中default
,required
和readonly
是可选关键字。
定义property
属性
以下示例定义了几种property
属性:
Item { property int someNumber property string someString property url someUrl property Item someItem property Rectangle someRectangle property var someVal property var someList: [1, 2, "three", "four"] property color nextColor onNextColorChanged: console.log("The next color will be: " + nextColor.toString()) }
除枚举类型外,属性类型支持其他所有的基本类型(枚举类型可以用int
替代)。另外,属性类型还可以是QML对象类型,如Item
,Rectangle
等,甚至可以是自定义的QML对象类型。var
用于类型占位符,可以保存任何类型的值。
定义property
属性时,QML会自动创建一个与该属性关联的信号处理程序。命名规则为on<PropertyName>Changed
,其中<PropertyName>
是属性的名称,首字母变为大写。如上面示例中的nextColor
属性和onNextColorChanged
信号处理程序。
property
属性赋值
属性赋值有两种方式:
- 初始化时赋值,语法
<propertyName> : <value>
。
import QtQuick Rectangle { color: "red" // 初始化时赋值 property color nextColor: "blue" // 属性声明同时进行初始化 }
- 使用赋值运算符赋值,语法
[<objectId>.]<propertyName> = value
。
import QtQuick Rectangle { id: rect Component.onCompleted: { rect.color = "red" // 使用赋值运算符进行赋值 } }
可以为属性赋值两种值:静态值或绑定表达式值(又称属性绑定)。区别在于属性值是否依赖于其他属性。示例如下:
import QtQuick Rectangle { // 赋值静态值 width: 400 height: 200 Rectangle { // 属性绑定 width: parent.width / 2 height: parent.height } }
对于属性绑定,当表达式中的属性值发生变化时,QML引擎会自动重新计算绑定表达式并将新结果赋值给该属性。
小贴士:QML中的属性是类型安全的,只能为属性赋值与属性类型匹配的值。
默认属性
一个QML对象最多只能有一个default
属性。如果对象定义了default
属性,那么在另一个对象中使用该对象时,可以省略对默认属性的赋值。
如下面的代码,在MyLabel.qml文件中定义一个默认属性someText。
// MyLabel.qml import QtQuick Text { default property Text someText text: "Hello, " + someText.text }
使用如下:
MyLabel { someText: Text { text: "world!" } }
由于使用了默认属性,所以可以简化如下:
MyLabel { Text { text: "world!" } }
必须属性
可以使用required
关键字定义必须属性,该属性不能具有初始值。必须在创建对象的实例时为该属性赋值。
下面的代码中定义了一个必须属性:
// MyRect.qml import QtQuick Rectangle { required property rect initRect x: initRect.x y: initRect.y width: initRect.width height: initRect.height }
所以在使用该对象时,必须为该属性赋值:
MyRect { initRect: Qt.rect(10, 10, 50, 50) color: "red" }
我们还可以把已经存在属性定义为必须属性,语法如下:
required <propertyName>
下面的示例表示在创建该对象时,必须指定color
属性:
// ColorRectangle.qml import QtQuick Rectangle { required color }
只读属性
可以使用readonly
关键字定义只读属性。顾名思义,该属性不允许修改,所以它必须具有初始值。语法如下:
readonly property <propertyType> <propertyName> : <initialValue>
下面的示例中,someNumber属性为只读属性,所以对它再次赋值是错误的:
Item { readonly property int someNumber: 10 // 只读属性在定义时赋值 Component.onCompleted: someNumber = 20 // 错误:不可以修改只读属性 }
小贴上:只读属性不可以是默认属性。
对象列表属性
定义对象列表属性的语法:
[default] property list<<objectType>> propertyName: <value>
值则为用方括号括起来的逗号分隔的列表:[ <item 1>, <item 2>, ... ]
。如下示例:
// RectangleList.qml import QtQuick Rectangle { // 只声明不做初始化 property list<Rectangle> siblingRects // 声明同时进行初始化 property list<Rectangle> childRects: [ Rectangle { color: "red" }, Rectangle { color: "blue"} ] }
实例化:
RectangleList { siblingRects: [ Rectangle { color: "red" }, Rectangle { color: "blue" } ] }
如果列表中只有一个元素,则方括号可以省略:
RectangleList { siblingRects: Rectangle { color: "red" } }
分组属性
有些属性会包含一组子属性,可以使用点符号或组符号为子属性赋值。如Text
对象类型具有font
组属性:
Text { // 使用点符号赋值 font.pixelSize: 12 font.bold: true } Text { // 使用组符号赋值 font { pixelSize: 12; bold: true } }
属性别名
属性别名使用alias
关键字进行定义,功能类似于C++中的引用,是用于保存另一个属性的引用,它不需要分配新的存储空间,并且属性定义的右侧必须是有效的别名引用:
[default] property alias <name>: <alias reference>
属性别名有以下限制:
- 它只能引用在声明别名的类型范围内的对象或对象的属性。
- 它不能包含任何JavaScript表达式。
- 它不能引用在其类型范围之外声明的对象。
- 它在定义时必须有值。
- 它不能引用附加属性。
- 它不能引用深度为3或更深的层次结构中的属性。
下面是一个属性别名常用的使用场景:
// Button.qml import QtQuick Rectangle { property alias buttonText: textItem.text width: 100; height: 30; color: "yellow" Text { id: textItem } }
实例化该对象:
Button { buttonText: "Click Me" }
这里为buttonText
赋值即为Button
对象类型里的textItem.text
赋值,效果完全一样。
信号属性
信号是来自某个对象的通知,表示发生了某些事件。当信号发出时,可以通过对应的信号处理程序进行处理。信号处理程序使用on<Signal>
语法声明,其中<Signal>
是信号名称,首字母变为大写。定义信号属性语法如下:
signal <signalName>[([<type> <parameter name>[, ...]])]
信号可以具有参数,当没有参数时,小括号可以省略。调用信号与调用方法的方式一致。
import QtQuick Item { signal clicked() // 无参数 signal hovered // 无参数,可以省略小括号 signal actionPerformed(string action, var actionResult) // 有两个参数 }
信号处理程序属性
信号处理程序是一种特殊的方法属性,只要发出相关的信号,QML引擎就会调用该方法。示例如下:
// SquareButton.qml import QtQuick Rectangle { id: root signal activated(real xPosition, real yPosition) signal deactivated property int side: 100 width: side; height: side MouseArea { anchors.fill: parent onPressed: root.activated(mouse.x, mouse.y) onReleased: root.deactivated() } }
// myapplication.qml SquareButton { onActivated: console.log("Activated at " + xPosition + "," + yPosition) onDeactivated: console.log("Deactivated!") }
QML引擎会自动为属性创建一个属性修改的信号处理程序。语法on<Property>Changed
,其中<Property>
是属性的名称,首字母变为大写。比如TextInput
具有text
属性,所以会自动拥有信号处理程序onTextChanged
:
import QtQuick TextInput { text: "Change this!" onTextChanged: console.log("Text has changed to:", text) }
方法属性
方法属性用于封装对象类型的某些操作。它可以与信号进行连接,以便在发出信号时自动调用该方法。
QML中定义方法属性语法如下:
function <functionName>([<parameterName>[, ...]]) { <body> }
与信号不同,方法的参数不需要声明参数类型,因为默认是var
类型。示例如下:
import QtQuick Item { width: 200; height: 200 MouseArea { anchors.fill: parent onClicked: label.moveTo(mouse.x, mouse.y) } Text { id: label function moveTo(newX, newY) { label.x = newX; label.y = newY; } text: "Move me!" } }
附加属性和附加信号处理程序属性
附加属性和附加信号处理程序是使对象能够使用其他属性或信号处理程序进行注释的机制,而附加属性和信号处理程序对于对象是不可用的。
附加属性和附加信号处理程序的使用语法:
<AttachingType>.<propertyName> <AttachingType>.on<SignalName>
如下示例:
import QtQuick ListView { width: 240; height: 320 model: 3 delegate: Rectangle { width: 100; height: 30 color: ListView.isCurrentItem ? "red" : "yellow" } }
isCurrentItem
就是ListView
类型的附加属性。使用方式为ListView.isCurrentItem
。
下面是附加信号处理程序的示例:
import QtQuick ListView { width: 240; height: 320 model: ListModel { id: listModel Component.onCompleted: { for (var i = 0; i < 10; i++) listModel.append({"Name": "Item " + i}) } } delegate: Text { text: index } }
onCompleted
为Component
类型的附加信号处理程序。使用方式为Component.onCompleted
。类似的还有Keys
类型的onPressed
附加信号处理程序等。
值得注意的是,附加属性只能被所属的对象访问,而不能被这个对象的子对象访问,或者作为属性别名暴露出去也是不允许的。如下面的示例是错误的:
import QtQuick ListView { width: 240; height: 320 model: 3 delegate: Item { width: 100; height: 30 Rectangle { width: 100; height: 30 color: ListView.isCurrentItem ? "red" : "yellow" // 错误:附加属性不能被子对象访问 } } }
因为ListView.isCurrentItem
只是附加在delegate
对象上,而没有附加在delegate
的子对象Rectangle
上。所以下面的代码就是正常的:
ListView { //.... delegate: Item { id: delegateItem width: 100; height: 30 Rectangle { width: 100; height: 30 color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // 正确 } } }
枚举属性
枚举属性提供了一组固定的名称选项,可以帮助我们实现更好的代码架构,提供可阅读性。枚举类型和枚举值必须都以大写字母开头。使用enum
关键字声明:
// MyText.qml Text { enum TextType { Normal, Heading } }
可以通过<Type>.<EnumerationType>.<Value>
或者<Type>.<Value>
使用枚举:
// MyText.qml Text { enum TextType { Normal, Heading } property int textType: MyText.TextType.Normal font.bold: textType == MyText.TextType.Heading font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12 }
获取更多信息,请关注作者公众号:程序员练兵场