QML 对象属性
每种 QML 对象类型都定义了一组属性。创建该对象类型的每个实例时,都会带有为该对象类型定义的这组属性。可以指定几种不同类型的属性,具体说明如下。
对象声明中的属性
QML 文档中的对象声明用于定义一种新类型。它还会声明一个对象层次结构,当创建该新定义类型的实例时,该层次结构将被实例化。
QML 对象类型的属性类型如下:
- id属性
- 属性属性
- 信号属性
- 信号处理程序属性
- 方法属性
- 附加属性及附加信号处理程序属性
- 枚举属性
下面将详细讨论这些属性。
id属性
一个 QML 元素最多只能有一个id属性。该属性由语言本身提供,任何 QML 对象类型都无法对其进行重新定义或覆盖。
可以为对象实例的id属性赋值,以便其他对象能够识别和引用该对象。该id 必须以小写字母或下划线开头,且不能包含字母、数字和下划线以外的字符。它也不能是 JavaScript 关键字。 有关此类关键字的列表,请参阅《ECMAScript 语言规范》。
如果您在 QML 中使用了不符合 JavaScript 标识符规范的名称(例如as),则无法在 JavaScript 中引用该标识对象,这将使该id基本失去作用。不过,您仍可通过 C++ 中的 `QQmlContext ` 与这些id进行交互。
下面是一个 `TextInput ` 对象和一个 `Text ` 对象。该 `TextInput ` 对象的 `id ` 值被设置为 "myTextInput"。该 `Text ` 对象通过引用 `myTextInput.text`,将其 `text ` 属性设置为与 `TextInput` 的 `text ` 属性具有相同的值。现在,这两个项将显示相同的文本:
import QtQuick
Column {
width: 200; height: 200
TextInput { id: myTextInput; text: "Hello World" }
Text { text: myTextInput.text }
}在创建该对象的QML 上下文内,可以从任何位置通过其id 引用该对象。因此,id 的值在其上下文中必须始终是唯一的。有关更多信息,请参阅“作用域和命名解析”。
该上下文还通过QQmlContext 层次结构向C++公开。例如,您可以通过qmlContext 函数获取特定对象的上下文,并查询同一上下文中的其他对象:
QObject *textInput = qmlContext(theColumn)->objectForName("myTextInput");一旦对象实例被创建,其id属性的值就无法更改。虽然它看起来像一个普通的属性,但id 属性并非普通的property 属性,对其适用特殊的语义;例如,在上述示例中无法访问myTextInput.id 。
属性
属性是对象的一个属性,可以被赋予静态值或绑定到动态表达式上。属性的值可以被其他对象读取。通常,它也可以被其他对象修改,除非某个特定的 QML 类型已明确禁止对特定属性进行修改。
定义属性
在 C++ 中,可以通过为类注册Q_PROPERTY (该类随后会被注册到 QML 类型系统中)来为某种类型定义属性。此外,也可以在 QML 文档的对象声明中使用以下语法定义对象类型的自定义属性:
[default] [virtual] [override] [final] [required] [readonly] property <propertyType> <propertyName>通过这种方式,对象声明可以更轻松地向外部对象公开特定值,或维护某些内部状态。
属性名称必须以小写字母开头,且只能包含字母、数字和下划线。JavaScript 保留字不能用作属性名称。default 、required 、readonly 、virtual 、override 、final 这些关键字是可选的,用于修改所声明属性的语义。 有关这些关键字各自含义的更多信息,请参阅后续关于默认属性、必填属性、只读属性以及覆盖语义的章节。
声明自定义属性会隐式地为该属性创建一个值变化信号,以及一个名为on<PropertyName>Changed 的关联信号处理程序,其中<PropertyName>是属性的名称,首字母大写。
例如,以下对象声明定义了一个从 Rectangle 基类派生的新类型。它具有两个新属性,其中为其中一个新属性实现了信号处理程序:
Rectangle {
property color previousColor
property color nextColor
onNextColorChanged: console.log("The next color will be: " + nextColor.toString())
}自定义属性定义中的有效类型
任何QML 值类型均可作为自定义属性类型使用。例如,以下均为有效的属性声明:
(枚举值本质上是整数值,可以使用int 类型来引用。)
某些值类型由QtQuick 模块提供,因此除非导入该模块,否则无法将其用作属性类型。更多详细信息请参阅QML值类型文档。
请注意,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 对象类型均可作为属性类型使用。例如:
property Item someItem
property Rectangle someRectangle这同样适用于自定义 QML 类型。如果某个 QML 类型定义在名为 `ColorfulButton.qml ` 的文件中(该文件所在的目录随后被客户端导入),那么类型为 `ColorfulButton ` 的属性也是有效的。
为属性赋值
对象实例的属性值可以通过两种不同的方式指定:
- 初始化时的值赋
- 命令式赋值
无论哪种情况,该值都可以是静态值,也可以是绑定表达式的值。
初始化时的值赋值
在初始化时为属性赋值的语法如下:
<propertyName> : <value>如果需要,初始化值赋值可以与对象声明中的属性定义结合使用。在这种情况下,属性定义的语法如下:
[default] property <propertyType> <propertyName> : <value>以下是一个属性值初始化的示例:
import QtQuick
Rectangle {
color: "red"
property color nextColor: "blue" // combined property declaration and initialization
}命令式值赋值
命令式赋值是指通过命令式 JavaScript 代码将属性值(无论是静态值还是绑定表达式)赋给属性。命令式赋值的语法即为 JavaScript 赋值运算符,如下所示:
[<objectId>.]<propertyName> = value以下是一个命令式值赋值的示例:
import QtQuick
Rectangle {
id: rect
Component.onCompleted: {
rect.color = "red"
}
}静态值与绑定表达式值
如前所述,可赋值给属性的值有两种:静态值和绑定表达式值。后者也称为属性绑定。
| 类型 | 语义 |
|---|---|
| 静态值 | 不依赖于其他属性的常量值。 |
| 绑定表达式 | 描述属性与其他属性之间关系的 JavaScript 表达式。该表达式中的变量称为该属性的依赖项。 QML 引擎会强制执行属性与其依赖项之间的关系。当任何一个依赖项的值发生变化时,QML 引擎会自动重新评估绑定表达式,并将新结果赋值给该属性。 |
以下示例展示了将这两种类型的值赋给属性的情况:
import QtQuick
Rectangle {
// both of these are static value assignments on initialization
width: 400
height: 200
Rectangle {
// both of these are binding expression value assignments on initialization
width: parent.width / 2
height: parent.height
}
}注意:若要以 命令式方式 赋值绑定表达式,该表达式必须包含在一个传递给 `Qt.binding()` 的函数中,然后将 `Qt.binding()` 返回的值赋给该属性。相反,在初始化时赋值绑定表达式时,不得使用 `Qt.binding()`。更多信息请参阅“属性绑定”。
类型安全
属性具有类型安全性。属性只能被赋予与该属性类型匹配的值。
例如,如果一个属性是 int 类型,而你试图向其赋值一个字符串,将会引发错误:
property int volume: "four" // generates an error; the property's object will not be loaded同样地,如果在运行时将错误类型的值赋给属性,新值将不会被赋予,并会引发错误。
某些属性类型没有天然的数值表示形式,对于此类属性类型,QML 引擎会自动执行字符串到类型化值的转换。因此,例如,尽管color 类型的属性存储的是颜色而非字符串,但您可以将字符串"red" 赋值给颜色属性,而不会报错。
有关默认支持的属性类型列表,请参阅QML 值类型。此外,任何可用的QML 对象类型均可作为属性类型使用。
特殊属性类型
对象列表属性
list 类型的属性可以被赋予一个由 QML 对象类型值组成的列表。定义对象列表值的语法是使用方括号包围的、以逗号分隔的列表:
[ <item 1>, <item 2>, ... ]例如,Item 类型有一个states 属性,用于存储State 类型对象的列表。以下代码将该属性的值初始化为包含三个State 对象的列表:
import QtQuick
Item {
states: [
State { name: "loading" },
State { name: "running" },
State { name: "stopped" }
]
}如果列表只包含一个项目,则可以省略方括号:
在对象声明中,可以使用以下语法指定list 类型的属性:
[default] property list<<ObjectType>> propertyName与其他属性声明一样,属性初始化可以与属性声明结合使用,语法如下:
[default] property list<<ObjectType>> propertyName: <value>以下是一个列表属性声明的示例:
import QtQuick
Rectangle {
// declaration without initialization
property list<Rectangle> siblingRects
// declaration with initialization
property list<Rectangle> childRects: [
Rectangle { color: "red" },
Rectangle { color: "blue"}
]
}若需声明一个用于存储值列表的属性,且这些值不一定是 QML 对象类型的值,则应声明一个 `var ` 属性。
分组属性
在某些情况下,属性包含一组逻辑上的子属性。这些子属性既可以通过点表示法,也可以通过组表示法进行赋值。
例如,Text 类型具有font 属性。下例中,第一个Text 对象使用点表示法初始化其font 值,而第二个则使用组表示法:
Text {
//dot notation
font.pixelSize: 12
font.bold: true
}
Text {
//group notation
font { pixelSize: 12; bold: true }
}对于类型本身具有子属性的任何属性,均可使用分组属性语法。这是一种表示法,而非独立的属性类型:无论该属性持有的是font 这样的值类型,还是对象类型,对语法而言均无影响。
不过,属性的类型确实会影响引擎需要执行的操作:
- 如果属性持有值类型,引擎会读取该值、对其进行修改,然后写回原处。因此,该属性必须是可写的。
- 如果属性存储的是值类型,则赋值操作将写入属性当前持有的对象中。在应用赋值操作时,该对象不能为空。 属性本身可以是只读的,也可以是可写的。将其设为只读,可以防止 QML 代码替换子属性所属的对象,从而避免对分组属性应应用于哪个对象产生混淆。这通常是一个好做法。
子属性的名称是根据该属性的声明类型进行解析的,而非根据运行时其所持有的对象的类型。此外,在同一个对象定义中,不能对同一个属性同时使用这两种形式:要么将一个对象赋值给该属性,要么直接对它的子属性进行赋值。
属性别名
属性别名是指持有另一个属性引用(reference)的属性。与普通属性定义(会为该属性分配一个新的、唯一的存储空间)不同,属性别名将新声明的属性(称为“别名属性”)作为对现有属性(“被别名属性”)的直接引用进行连接。
属性别名声明与普通属性定义相似,区别在于它需要使用alias 关键字代替属性类型,且属性声明的右侧必须是一个有效的别名引用:
[default] property alias <name>: <alias reference>与普通属性不同,别名具有以下限制:
- 它只能引用位于声明该别名所在类型作用域内的对象,或该对象的属性。
- 它不能包含任意的 JavaScript 表达式
- 它不能引用在其类型作用域之外声明的对象。
- 与普通属性的可选默认值不同,别名引用并非可选的;在首次声明别名时,必须提供别名引用。
- 它不能引用附加属性。
- 它不能引用深度为 3 或更大的层次结构中的属性。以下代码将无法运行:
property alias color: myItem.myRect.border.color Item { id: myItem property Rectangle myRect }但是,深度不超过两级的属性别名是可以正常工作的。
property alias color: rectangle.border.color Rectangle { id: rectangle }
例如,下面是一个Button 类型,其中buttonText 属性被别名化,并连接到Text 子对象的text 对象:
// Button.qml
import QtQuick
Rectangle {
property alias buttonText: textItem.text
width: 100; height: 30; color: "yellow"
Text { id: textItem }
}以下代码将创建一个Button ,其中为子对象Text 定义了文本字符串:
Button { buttonText: "Click Me" }在此,修改buttonText 会直接修改 textItem.text 的值;它不会先更改某个其他值,再由该值间接更新 textItem.text。 如果 `buttonText ` 不是别名,那么更改其值实际上根本不会改变显示的文本,因为属性绑定不是双向的:如果 `textItem.text` 被更改,`buttonText ` 的值也会随之改变,但反之则不会。
属性别名与类型
属性别名不能有显式的类型声明。属性别名的类型即为其所引用的属性或对象的声明类型。因此,如果你为一个通过 id 引用的对象创建别名,而该对象内联声明了额外属性,则无法通过该别名访问这些额外属性:
// MyItem.qml
Item {
property alias inner: innerItem
Item {
id: innerItem
property int extraProperty
}
}您无法从该组件外部初始化inner.extraProperty ,因为inner仅是一个Item :
// main.qml
MyItem {
inner.extraProperty: 5 // fails
}不过,如果你将 `inner` 对象提取到一个带有独立 .qml 文件的单独组件中,就可以实例化该组件,并通过别名访问其所有属性:
// MainItem.qml
Item {
// Now you can access inner.extraProperty, as inner is now an ExtraItem
property alias inner: innerItem
ExtraItem {
id: innerItem
}
}
// ExtraItem.qml
Item {
property int extraProperty
}默认属性
一个对象定义可以拥有一个默认属性。当一个对象直接嵌套在另一个对象内部且未指定属性时,它会自动被赋值为外围对象的默认属性。
使用可选的关键字default 声明属性,可将其标记为默认属性。例如,假设有一个名为Framer.qml的文件,其中包含默认属性focusItem :
// Framer.qml
import QtQuick
Row {
default property Item focusItem
property Item leftItem: Rectangle {
width: 10
height: parent.height
color: "red"
}
property Item rightItem: Rectangle {
width: 10
height: parent.height
color: "blue"
}
children: [leftItem, focusItem, rightItem]
}可以在 `Framer ` 对象定义中为 `focusItem ` 值赋值,如下所示:
Framer {
Text { text: "Hello, world!" }
}这与以下写法效果完全相同:
Framer {
focusItem: Text { text: "Hello, world!" }
}然而,由于focusItem 属性已被标记为默认属性,因此无需显式地将Text 对象赋值给该属性。
虽然任何类型的属性都可以被标记为default 属性,但通常只有将var 类型、object类型及其各自的序列类型的属性标记为 属性才有实际意义:由于只有对象实例会被赋值给 属性,因此在QML中,例如将default 字符串属性标记为 属性并无实际意义。
考虑以下 TextHolder 类型:
// TextHolder.qml
Item {
property default string mytext
}单就这一点而言,这没有问题。但是,如果不显式指定属性名称,就无法将字符串字面量赋值给mytext :
TextHolder {
/* The following would be a syntax error, and will not assign
to the mytext property:
"some text"
The line below is the only way to assign the value:
\1/
mytext: "some text"
}你会注意到,可以将子对象添加到任何基于Item 的类型中,而无需将其显式添加到children 属性中。这是因为Item 的默认属性是其data 属性,且为Item 添加到该列表中的任何项都会自动添加到其children 列表中。
默认属性对于重新分配项目的子项非常有用。例如:
通过将默认属性别名设置为 `inner.children`,任何被指定为外部项子项的对象都会自动重新分配为内部项的子项。
警告:设置 元素默认列表属性的值可以采用隐式或显式方式。在单个元素的定义中,这两种方法不得混合使用,否则会导致列表中元素的排序不确定。
Item {
// Use either implicit or explicit assignement to the default list property but not both!
Rectangle { width: 40 } // implicit
data: [ Rectangle { width: 100 } ] // explicit
}重写语义
默认情况下,属性可以被遮蔽:您可以在派生 QML 类型中重新声明一个属性,可能带有新的类型和新的属性。这会导致存在两个同名的属性,但在任何给定上下文中只能访问其中一个。这通常并非您所期望的结果。 这通常是无意的,而且大多数情况下其影响会相当令人困惑。此外,遮蔽对工具支持不利。
为解决此问题,引入了virtual 、override 、final 等关键字,以及相应的警告和错误提示。
有关更多详细信息以及包括警告和错误在内的全面示例集,请参阅“属性遮蔽与重写语义”页面。
必填属性
对象声明可以使用required 关键字将属性定义为必填。语法如下
required property <propertyType> <propertyName>顾名思义,在创建对象实例时必须设置必填属性。如果静态检测到违反此规则,将导致 QML 应用程序无法启动。对于动态实例化的 QML 组件(例如通过Qt.createComponent()),违反此规则将引发警告并返回 null 值。
可以通过以下方式将现有属性设为必填:
required <propertyName>以下示例演示了如何创建一个自定义 Rectangle 组件,其中 color 属性必须始终指定。
// ColorRectangle.qml
Rectangle {
required color
}注意:您 无法在 QML 中为必填属性赋初始值,因为这将直接违背必填属性的预期用途。
必填属性在模型-视图-委托(MVD)代码中起着特殊的作用:如果视图的委托具有其名称与视图模型的角色名称相匹配的必填属性,则这些属性将使用模型的相应值进行初始化。有关更多信息,请访问 Qt Quick页面中的“模型与视图”部分。
有关如何从 C++ 初始化必需属性的方法,请参阅QQmlComponent::createWithInitialProperties 、QQmlApplicationEngine::setInitialProperties 以及QQuickView::setInitialProperties 。
只读属性
对象声明可以使用readonly 关键字定义只读属性,语法如下:
readonly property <propertyType> <propertyName> : <value>只读属性在初始化时必须被赋予静态值或绑定表达式。只读属性初始化完成后,其静态值或绑定表达式将无法再被更改。
例如,以下 `Component.onCompleted ` 代码块中的代码是无效的:
Item {
readonly property int someNumber: 10
Component.onCompleted: someNumber = 20 // TypeError: Cannot assign to read-only property
}注意: 只读属性 不能同时作为默认属性。
属性修饰符对象
属性可以关联属性值修饰符对象。声明与特定属性关联的属性修饰符类型实例的语法如下:
<PropertyModifierTypeName> on <propertyName> {
// attributes of the object instance
}这通常被称为“on”语法。
需要注意的是,上述语法实际上是一个对象声明,它将实例化一个作用于预先存在的属性的对象。
某些属性修饰符类型可能仅适用于特定的属性类型,但语言本身并不强制执行这一限制。 例如,由QtQuick 提供的 `NumberAnimation ` 类型仅会对数值型(如int 或real )属性进行动画处理。尝试将 `NumberAnimation ` 用于非数值型属性虽不会引发错误,但该非数值型属性将无法被动画化。属性修饰符类型在与特定属性类型关联时的行为由其实现定义。
信号属性
信号是对象发出的通知,表示某些事件已发生:例如,属性已更改、动画已开始或停止,或者图像已下载完毕。例如,MouseArea 类型具有一个clicked 信号,当用户在鼠标区域内点击时,该信号会被触发。
每当发出特定信号时,可以通过信号处理程序向对象发送通知。信号处理程序的声明语法为on<Signal>,其中<Signal>是信号的名称,首字母大写。 信号处理程序必须声明在发出该信号的对象的定义范围内,且该处理程序应包含在被调用时需执行的 JavaScript 代码块。
例如,下面的onClicked信号处理程序在MouseArea 对象定义中声明,当点击MouseArea 时会被调用,从而在控制台打印一条消息:
import QtQuick
Item {
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Click!")
}
}
}定义信号属性
在 C++ 中,可以通过注册一个类的 `Q_SIGNAL ` 并将其注册到 QML 类型系统中,为某种类型定义信号。此外,也可以在 QML 文档的对象声明中,使用以下语法为对象类型定义自定义信号:
signal <signalName>[([<parameterName>: <parameterType>[, ...]])]在同一类型块中尝试声明两个同名的信号或方法将导致错误。但是,新信号可以复用该类型上现有信号的名称。(此操作应谨慎进行,因为现有信号可能会被隐藏而无法访问。)
以下是三个信号声明的示例:
import QtQuick
Item {
signal clicked
signal hovered()
signal actionPerformed(action: string, actionResult: int)
}您还可以使用属性风格的语法指定信号参数:
signal actionCanceled(string action)为了与方法声明保持一致,建议优先使用冒号进行类型声明。
如果信号没有参数,则“()”括号是可选的。如果使用了参数,则必须声明参数类型,例如上文actionPerformed 信号中的string 和int 参数。允许的参数类型与本页“定义属性属性”部分中列出的类型相同。
要发出信号,请将其作为方法调用。当信号发出时,所有相关的信号处理程序都会被调用,处理程序可以使用已定义的信号参数名称来访问相应的参数。
属性变化信号
QML 类型还提供了内置的属性变化信号,这些信号会在属性值发生变化时触发,正如前文“属性属性”一节所述。关于这些信号的用途及其使用方法的更多信息,请参阅后续关于属性变化信号处理程序的部分。
信号处理程序属性
信号处理程序是一种特殊类型的方法属性,当关联的信号被发出时,QML 引擎会调用该方法的实现。在 QML 中向对象定义添加信号时,系统会自动向该对象定义添加一个关联的信号处理程序,其默认实现为空。 客户端可以提供实现代码,以实现程序逻辑。
考虑以下SquareButton 类型,其定义如下所示,位于SquareButton.qml 文件中,包含activated 和deactivated 两个信号:
// SquareButton.qml
Rectangle {
id: root
signal activated(xPosition: real, yPosition: real)
signal deactivated
property int side: 100
width: side; height: side
MouseArea {
anchors.fill: parent
onReleased: root.deactivated()
onPressed: mouse => root.activated(mouse.x, mouse.y)
}
}同一目录下另一个 QML 文件中的任何SquareButton 对象均可接收这些信号,其中信号处理程序的实现由客户端提供:
// myapplication.qml
SquareButton {
onDeactivated: console.log("Deactivated!")
onActivated: (xPosition, yPosition) => {
console.log(`Activated at ${xPosition}, ${yPosition}`)
}
}信号处理程序无需声明其参数类型,因为信号本身已指定了这些类型。上文所示的箭头函数语法不支持类型注释。
有关信号使用的更多详细信息,请参阅《信号与处理程序事件系统》。
属性变化信号处理程序
属性变化信号的信号处理程序采用on<Property>Changed的语法形式,其中<Property>是属性名称,首字母大写。 例如,尽管TextInput 类型的文档中未记录textChanged 信号,但由于TextInput 具有text 属性,因此该信号隐式可用,从而可以编写onTextChanged 信号处理程序,在该属性发生变化时被调用:
import QtQuick
TextInput {
text: "Change this!"
onTextChanged: console.log(`Text has changed to: ${text}`)
}方法属性
对象类型的方法是一种函数,可用于执行某些处理或触发后续事件。方法可以与信号关联,从而在信号被发出时自动调用。更多详细信息请参阅“信号与处理程序事件系统”。
定义方法属性
在 C++ 中,可以通过为类中的函数添加标记,然后使用 `Q_INVOKABLE ` 将其注册到 QML 类型系统中,或者将其注册为类的 `Q_SLOT ` 来为类型定义方法。此外,还可以使用以下语法在 QML 文档的对象声明中添加自定义方法:
function <functionName>([<parameterName>[: <parameterType>][, ...]]) [: <returnType>] { <body> }可以在 QML 类型中添加方法,以定义独立且可重用的 JavaScript 代码块。这些方法既可在内部调用,也可由外部对象调用。
与信号不同,方法参数类型无需显式声明,其默认类型为var 。不过,为了帮助qmlcachegen生成性能更优的代码并提高可维护性,建议您进行声明。
在同一类型块中尝试声明两个同名的方法或信号将导致错误。但是,新方法可以复用该类型上现有方法的名称。(此操作应谨慎进行,因为现有方法可能会被隐藏而无法访问。)
下面是一个Rectangle ,其中包含一个calculateHeight() 方法,该方法在赋值height 时会被调用:
import QtQuick
Rectangle {
id: rect
function calculateHeight(): real {
return rect.width / 2;
}
width: 100
height: calculateHeight()
}如果方法带有参数,则可在方法内部通过名称访问这些参数。下例中,当点击MouseArea 时,会调用moveTo() 方法,该方法可引用接收到的newX 和newY 参数来重新定位文本:
import QtQuick
Item {
width: 200; height: 200
MouseArea {
anchors.fill: parent
onClicked: mouse => label.moveTo(mouse.x, mouse.y)
}
Text {
id: label
function moveTo(newX: real, newY: real) {
label.x = newX;
label.y = newY;
}
text: "Move me!"
}
}附加属性与附加信号处理程序
附加属性和 附加信号处理程序是一种机制,它允许为对象添加额外的属性或信号处理程序,这些属性或信号处理程序在没有该机制的情况下本不可用。特别是,它们允许对象访问与该特定对象密切相关的属性或信号。
QML 类型的实现可以选择在 C++ 中创建一个具有特定属性和信号 的附加类型。 随后可以在运行时创建该类型的实例并将其附加到特定对象上,从而使这些对象能够访问附加类型的属性与信号。访问时,需在属性及相应信号处理程序名前添加附加类型的名称。
对附加属性和处理程序的引用采用以下语法形式:
<AttachingType>.<propertyName>
<AttachingType>.on<SignalName>例如,ListView 类型有一个附加属性ListView.isCurrentItem ,ListView 中的每个委托对象均可使用该属性。每个委托对象都可以利用该属性来判断自身是否为视图中当前选中的项目:
import QtQuick
ListView {
width: 240; height: 320
model: 3
delegate: Rectangle {
width: 100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow"
}
}在这种情况下,附加类型的名称为 `ListView `,相关属性为 `isCurrentItem`,因此该附加属性被称为 `ListView.isCurrentItem`。
附加信号处理程序的引用方式与此相同。例如,Component.onCompleted 附加信号处理程序通常用于在组件创建过程完成后执行某些 JavaScript 代码。在下面的示例中,一旦ListModel 完全创建完毕,其Component.onCompleted 信号处理程序将自动被调用以填充模型:
import QtQuick
ListView {
width: 240; height: 320
model: ListModel {
id: listModel
Component.onCompleted: {
for (let i = 0; i < 10; i++) {
append({ Name: `Item ${i}` })
}
}
}
delegate: Text { text: index }
}由于附加类型的名称为 `Component `,且该类型具有 `completed ` 信号,因此该附加信号处理程序被称为 `Component.onCompleted`。
关于访问附加属性和信号处理程序的说明
一个常见的误区是认为,这些属性已附加到的对象的子对象可以直接访问附加的属性和信号处理程序。事实并非如此。附加类型的实例仅附加到特定的对象上,而非附加到该对象及其所有子对象上。
例如,下面是之前涉及附加属性的示例的修改版本。这次,委托是Item ,而彩色Rectangle 是该项的子项:
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" // WRONG! This won't work.
}
}
}这无法按预期工作,因为ListView.isCurrentItem 仅附加到根委托对象,而非其子对象。由于Rectangle 是委托的子对象,而非委托本身,因此它无法通过ListView.isCurrentItem 访问isCurrentItem 附加属性。因此,矩形应通过根委托访问isCurrentItem :
ListView {
delegate: Item {
id: delegateItem
width: 100; height: 30
Rectangle {
width: 100; height: 30
color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // correct
}
}
}现在,delegateItem.ListView.isCurrentItem 已正确指向委托的isCurrentItem 附加属性。
枚举属性
枚举提供了一组固定的命名选项。可以在 QML 中使用enum 关键字进行声明:
// 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
}有关在 QML 中使用枚举的更多信息,请参阅QML 枚举文档。
在 Qt 5.10 中引入了在 Qml 中声明枚举的功能。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.