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 属性设置为与TextInputtext 属性具有相同的值。现在,两个项目都将显示相同的文本:

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] [required] [readonly] property <propertyType> <propertyName>

这样,对象声明就能更容易地向外部对象公开特定值或保持某些内部状态。

属性名必须以小写字母开头,且只能包含字母、数字和下划线。JavaScript 保留字不是有效的属性名。defaultrequiredreadonly 关键字是可选的,用于修改所声明属性的语义。有关默认属性必填属性只读属性各自含义的更多信息,请参阅接下来的章节。

声明自定义属性会隐式地为该属性创建一个值变化信号,以及一个名为on<PropertyName>Changed 的相关信号处理程序,其中<PropertyName>是属性名称,第一个字母大写。

例如,下面的对象声明定义了一个从矩形基本类型派生的新类型。它有两个新属性,并为其中一个新属性实现了信号处理程序

Rectangle {
    property color previousColor
    property color nextColor
    onNextColorChanged: console.log("The next color will be: " + nextColor.toString())
}
自定义属性定义中的有效类型

任何QML 值类型都可用作自定义属性类型。例如,这些都是有效的属性声明:

Item {
    property int someNumber
    property string someString
    property url someUrl
}

(枚举值是简单的整数值,可以用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" }
    ]
}

如果列表只包含一个项目,方括号可以省略:

import QtQuick

Item {
    states: State { name: "running" }
}

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.b: true
}

Text {
    //group notation
    font { pixelSize: 12; b: true }
}

分组属性类型是具有子属性的类型。如果分组属性类型是对象类型(而不是值类型),则持有该类型的属性必须是只读的。这是为了防止替换子属性所属的对象。

属性别名

属性别名是持有另一个属性引用的属性。与为属性分配新的、唯一存储空间的普通属性定义不同,属性别名将新声明的属性(称为别名属性)作为对现有属性(被别名属性)的直接引用连接起来。

属性别名声明与普通的属性定义相似,只是需要使用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 }
}

以下代码将为子Text 对象创建一个带有定义文本字符串的Button

Button { buttonText: "Click Me" }

在这里,修改buttonText 会直接修改 textItem.text 的值;而不会修改其他值,然后更新 textItem.text。如果buttonText 不是别名,更改其值实际上根本不会改变显示的文本,因为属性绑定不是双向的:如果 textItem.text 被更改,buttonText 的值就会改变,反之则不会。

属性别名的注意事项

别名属性有可能与现有属性同名,从而有效覆盖现有属性。例如,以下 QML 类型有一个color 别名属性,与内置的Rectangle::color 属性同名:

Rectangle {
    id: coloredrectangle
    property alias color: bluerectangle.color
    color: "red"

    Rectangle {
        id: bluerectangle
        color: "#1234ff"
    }

    Component.onCompleted: {
        console.log (coloredrectangle.color)    //prints "#1234ff"
        setInternalColor()
        console.log (coloredrectangle.color)    //prints "#111111"
        coloredrectangle.color = "#884646"
        console.log (coloredrectangle.color)    //prints #884646
    }

    //internal function that has access to internal properties
    function setInternalColor() {
        color = "#111111"
    }
}

任何使用该类型并引用其color 属性的对象都将引用别名,而不是普通的Rectangle::color 属性。但在内部,矩形可以正确设置其color 属性,并引用实际定义的属性而不是别名。

属性别名和类型

属性别名不能有明确的类型说明。属性别名的类型是其引用的属性或对象的声明类型。因此,如果为一个通过 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
}

但是,如果将内部对象提取到一个单独的组件中,并使用专用的 .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 关键字声明属性时,会将其标记为默认属性。例如,有一个文件 MyLabel.qml,其中有一个默认属性someText

// MyLabel.qml
import QtQuick

Text {
    default property var someText

    text: `Hello, ${someText.text}`
}

可以在MyLabel 对象定义中为someText 赋值,就像这样:

MyLabel {
    Text { text: "world!" }
}

这样做的效果与下文完全相同:

MyLabel {
    someText: Text { text: "world!" }
}

不过,由于someText 属性已被标记为默认属性,因此没有必要将Text 对象显式赋值给该属性。

您会发现,子对象可以添加到任何基于Item 的类型中,而无需显式地将它们添加到children 属性中。这是因为Item 的默认属性是其data 属性,而为Item 添加到此列表中的任何项目都会自动添加到其children 列表中。

默认属性可用于重新分配项目的子项。例如

Item {
    default property alias content: inner.children

    Item {
        id: inner
    }
}

通过将默认属性别名设置为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
}

必填属性

对象声明可以使用required 关键字将一个属性定义为必填属性。语法为

required property <propertyType> <propertyName>

顾名思义,必填属性必须在创建对象实例时设置。如果能静态检测到,违反此规则将导致 QML 应用程序无法启动。对于动态实例化的 QML 组件(例如通过Qt.createComponent() ),违反此规则会导致警告和返回值为空。

可以通过以下方法使现有属性成为必填属性

required <propertyName>

下面的示例展示了如何创建一个自定义矩形(Rectangle)组件,其中的颜色属性始终需要指定。

// ColorRectangle.qml
Rectangle {
    required color
}

注意: 你不能为 QML 的必填属性分配初始值,因为这直接违背了必填属性的预期用途。

必填属性在模型-视图-委托代码中起着特殊作用:如果视图的委托具有名称与视图模型的角色名称一致的必填属性,那么这些属性将被初始化为模型的相应值。更多信息,请访问 Qt Quick 中的"模型和视图"页面。

有关从 C++ 初始化必填属性的方法,请参阅QQmlComponent::createWithInitialPropertiesQQmlApplicationEngine::setInitialPropertiesQQuickView::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 类型只能激活数字类型(如intreal )的属性。尝试使用带有非数值型属性的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 信号的stringint 参数。允许的参数类型与本页 "定义属性"中列出的参数类型相同。

要发射信号,可将其作为方法调用。发出信号时,将调用任何相关的信号处理程序,处理程序可使用定义的信号参数名访问相应的参数。

属性更改信号

QML 类型还提供内置的属性变化信号,当属性值发生变化时,这些信号就会发出,这在前面有关属性属性的章节中已有描述。有关这些信号为何有用以及如何使用的更多信息,请参阅接下来有关属性变化信号处理器的章节。

信号处理程序属性

信号处理程序是一种特殊的方法属性,每当相关信号发出时,QML 引擎就会调用该方法的实现。在 QML 的对象定义中添加信号,会自动为对象定义添加相关的信号处理器,默认情况下,信号处理器的实现是空的。客户端可以提供一个实现,以实现程序逻辑。

考虑下面的SquareButton 类型,它的定义在SquareButton.qml 文件中提供,如下图所示,信号activateddeactivated

// 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 生成性能更高的代码并提高可维护性,您应该声明这些参数类型。

试图在同一类型块中声明两个同名的方法或信号是错误的。不过,新方法可以重复使用该类型上现有方法的名称。(这种做法应谨慎,因为现有方法可能会被隐藏而无法访问)。

下面是带有calculateHeight() 方法的Rectangle ,该方法在为height 赋值时被调用:

import QtQuick
Rectangle {
    id: rect

    function calculateHeight(): real {
        return rect.width / 2;
    }

    width: 100
    height: calculateHeight()
}

如果方法有参数,则可以通过方法中的名称访问这些参数。下图中,当点击MouseArea 时,会调用moveTo() 方法,然后该方法可以引用接收到的newXnewY 参数来重新定位文本:

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 Qml 5.10 中引入了在 QML 中声明枚举的功能。

© 2025 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.