每个 QML 对象类型都有一组已定义的属性。对象类型的每个实例都是使用为该对象类型定义的属性集创建的。
一、id 属性
每个 QML 对象类型都只有一个 id 属性。 该属性由语言本身提供,不能被任何 QML 对象类型重新定义或覆盖。
id 可用于其他对象识别和引用该对象。
id 必须以小写字母或下划线开头,并且不能包含字母、数字和下划线以外的字符。
一旦创建了对象实例,其 id 属性的值就无法更改。
二、自定义属性
property
是QML自定义属性修饰符。
2.1、定义属性
通过注册一个类的
Q_PROPERTY
,然后在 QML 类型系统中注册,可以为 C++ 中的类型定义一个属性。或者,可以使用以下语法在 QML 文档的对象声明中定义对象类型的自定义属性:
[
default
] [required] [
readonly
]
property
<propertyType> <propertyName>
通过这种方式,对象声明可以将特定值暴露给外部对象或更容易地维护一些内部状态。
属性名称必须
以小写字母开头
,并且只能包含字母、数字和下划线。
default
、
required
和
readonly
关键字是可选的,用于修改所声明属性的语义。
声明自定义属性隐式地为该属性创建一个值更改信号,以及一个名为
on<PropertyName>Changed
的关联信号处理程序,其中
<PropertyName>
是属性的名称,首字母大写。
例如,以下对象声明定义了一个派生自 Rectangle 基类型的新类型。它有两个新属性,并为其中一个新属性实现了信号处理程序:
Rectangle
{
property color previousColor
property color nextColor
onNextColorChanged: console.log("下一个颜色将是: " + nextColor.toString())
}
2.2、自定义属性定义中的有效类型
除了枚举类型之外的任何 QML 基本类型都可以用作自定义属性类型(枚举值只是整数值,可以用 int 类型代替。)。
property int someNumber
property string someString
property url someUrl
var 是一个通用的占位符类型,可以保存任何类型的值,包括列表和对象:
property var someNumber: 1.5
property var someString: "abc"
property var someBool: true
property var someList: [1, 2, "three", "four"]
property var someObject: Rectangle { width: 100; height: 100; color: "red" }
此外,任何 QML 对象类型(包括自定义QML类型)都可以用作属性类型。
property Item someItem
property Rectangle someRectangle
2.3、类型安全
属性是类型安全的。 只能为属性分配与属性类型匹配的值。
例如,如果一个属性是一个实数,如果试图给它分配一个字符串,就会报错:
property int volume: "four" // 报错
某些属性类型没有自然值表示,对于这些属性类型,QML 引擎会自动执行字符串到类型值的转换。例如,即使颜色类型的属性存储颜色而不是字符串,也可以将字符串“red”分配给颜色属性。
2.4、特殊属性类型
2.4.1、对象列表属性
定义对象列表值的语法是用方括号括起来的逗号分隔列表:
[ <item 1>, <item 2>, ... ]
例如,
Item
类型的
states
属性,用于保存
State
类型对象的列表。
import QtQuick 2.0
Item {
states: [
State { name: "loading" },
State { name: "running" },
State { name: "stopped" }
]
}
如果列表包含单个项目,则可以省略方括号:
import QtQuick 2.0
Item {
states: State { name: "running" }
}
可以使用以下语法在对象声明中指定列表类型属性:
[
default
]
property
list<<objectType>> propertyName
import QtQuick 2.0
Rectangle {
// // 没有初始化的声明
property list<Rectangle> siblingRects
// 带初始化的声明
property list<Rectangle> childRects: [
Rectangle { color: "red" },
Rectangle { color: "blue"}
]
}
2.4.2、分组属性
在某些情况下,属性包含子属性属性的逻辑组。 可以使用
点表示法
或
组表示法
来分配这些子属性属性。
Text {
//点表示法
font.pixelSize: 12
font.bold : true
}
Text {
//组表示法
font { pixelSize: 12; bold : true }
}
2.5、属性别名
属性别名是保存对另一个属性的引用
的属性
。与为属性分配新的唯一存储空间的普通属性定义不同,属性别名将新声明的属性连接为对现有属性的直接引用。
属性别名声明看起来像一个普通的属性定义,除了它需要
alias
关键字而不是属性类型,并且属性声明的右侧必须是有效的别名引用:
[
default
]
property
alias
<name>: <alias reference>
与普通属性不同,别名具有以下限制:
- 它只能引用在声明别名的类型范围内的对象或对象的属性。
- 它不能包含任意的 JavaScript 表达式
- 它不能引用在其类型范围之外声明的对象。
- 它在首次声明别名时必须提供别名引用。
- 它不能引用附加属性。
- 它不能引用深度为 3 或更大的层次结构内的属性。此代码将不起作用:
property alias color: myItem.myRect.border.color
Item {
id: myItem
property Rectangle myRect
}
例如,下面是一个带有 buttonText 别名属性的 Button 类型,该属性连接到 Text 子项的文本对象:
// Button.qml
import QtQuick 2.0
Rectangle {
property alias buttonText: textItem.text
width: 100; height: 30; color: "yellow"
Text { id: textItem }
}
以下代码将为子 Text 对象创建一个带有已定义文本字符串的 Button:
Button { buttonText: "Click Me" }
修改 buttonText 将直接修改textItem.text的值。这可以用于在定义控件时设置可在外部修改的属性
。
2.5.1、属性别名的注意事项
- 引用未初始化的别名时会生成错误。
- 引用另一个别名属性时会生成错误。
- 别名属性可能与现有属性同名,从而可以覆盖现有属性。
2.6、默认属性
一个对象定义可以有
一个
默认属性。使用可选的
default
关键字声明属性将其标记为默认属性。
2.7、必要属性
对象声明可以使用
required
关键字定义对象实例时
必须设置的属性
。
required property
<propertyType> <propertyName>
或
required
<propertyName>
如果可以静态检测,缺少必要属性将导致 QML 应用程序无法启动。在动态实例化 QML 组件的情况下(例如通过
Qt
.
createComponent
()),缺少必要属性会导致警告和空返回值。
// ColorRectangle.qml
Rectangle {
required color
}
不能为 QML 中的必需属性分配初始值,因为这会直接违背必需属性的预期用途。
2.8、只读属性
对象声明可以使用 readonly 关键字定义只读属性。
readonly property
<propertyType> <propertyName> : <initialValue>
必须在初始化时为只读属性分配一个值。只读属性初始化后,无论是通过命令式代码还是其他方式,都无法再为其赋值。
只读属性不能同时是默认属性。
2.9、属性修饰符对象
属性可以具有与其关联的属性值修饰符对象。
声明与特定属性关联的属性修饰符类型的实例的语法如下:
<PropertyModifierTypeName> on <propertyName>
{
// 对象实例的属性
}
NumberAnimation on x
{
to: 50; duration: 1000
}
这通常称为“on”语法。上述语法实际上是一个对象声明,它将实例化一个对象,该对象作用于预先存在的属性。
三、信号属性
信号是来自对象的某个事件发生的通知。
每当发出特定信号时,都可以通过信号处理程序通知对象。
信号处理程序使用
on<Signal>
语法声明,其中 <Signal> 是信号的名称,首字母大写。
信号处理程序必须在发出信号的对象的定义中声明
,并且处理程序应包含调用信号处理程序时要执行的 JavaScript 代码块。
import QtQuick 2.0
Item {
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Click!")
}
}
}
3.1、定义信号属性
可以通过注册一个 C++ 中的类型定义一个信号,然后将其注册到 QML 类型系统。 或者,可以使用以下语法在 QML 文档的对象声明中定义对象类型的自定义信号:
signal
<signalName>[([<type> <parameter name>[, …]])]
import QtQuick 2.0
Item {
signal clicked
signal hovered()
signal actionPerformed(string action, var actionResult)
}
如果信号没有参数,则“()”括号是可选的。 如果使用参数,则必须声明参数类型。
要发出信号,请将其作为方法调用。
四、方法属性
方法是一个函数。方法可以连接到信号,以便在发出信号时自动调用它。
4.1、定义方法属性
可以通过标记类的函数在 C++ 中为类型定义方法,然后使用
Q_INVOKABLE
将其注册到 QML 类型系统,或将其注册为类的
Q_SLOT
。 或者可以使用以下语法将自定义方法添加到 QML 文档中的对象声明中:
function
<functionName>([<parameterName>[, …]]) { <body> }
可以将方法添加到 QML 类型以定义独立的、可重用的 JavaScript 代码块。 这些方法可以在内部或由外部对象调用。
与信号不同,
方法参数类型不必声明
,因为它们默认为 var 类型。
下面是一个带有 calculateHeight() 方法的矩形,该方法在分配高度值时被调用:
import QtQuick 2.0
Rectangle {
id: rect
function calculateHeight() {
return rect.width / 2;
}
width: 100
height: calculateHeight()
}
五、附加属性和附加信号处理程序
附加属性和附加信号处理程序是一种机制,使对象能够使用额外属性或信号处理程序。特别地,它们
允许对象访问与单个对象特别相关的属性或信号
。
QML 类型实现可以选择在 C++ 中创建具有特定属性和信号的附加类型。然后可以在运行时创建此类型的实例并将其附加到特定对象,从而允许这些对象访问附加类型的属性和信号。 这些是通过使用附加类型的名称为属性和相应的信号处理程序添加前缀来访问的。
对附加属性和处理程序的引用采用以下语法形式:
<AttachingType>.<propertyName>
<AttachingType>.on<SignalName>
例如,
ListView
类型有一个附加属性
ListView
.
isCurrentItem
,可用于
ListView
中的每个委托对象。每个单独的委托对象都可以使用它来确定它是否是视图中当前选定的项目:
import QtQuick 2.0
ListView {
width: 240; height: 320
model: 3
delegate: Rectangle {
width: 100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow"
}
}
附加的信号处理程序以相同的方式引用。例如,
Component
.
onCompleted
附加信号处理程序通常用于在组件的创建过程完成时执行一些 JavaScript 代码。
import QtQuick 2.0
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 }
}
六、枚举属性
枚举提供了一组固定的命名选择。 可以使用 enum 关键字在 QML 中声明它们:
// MyText.qml
Text {
enum TextType {
Normal,
Heading
}
}
如上所示,枚举类型(例如 TextType)和值(例如 Normal)必须以大写字母开头。
值通过
<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
}