QML对象属性

本文详细介绍了QML对象的各种属性,包括id属性、定义属性、信号属性、信号处理程序属性、方法属性等。属性可以是静态值或动态绑定,有默认、只读和对象列表等多种类型。此外,还讲解了如何定义和使用枚举属性,以及附加属性和附加信号处理程序属性的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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>

其中defaultrequiredreadonly是可选关键字。

定义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对象类型,如ItemRectangle等,甚至可以是自定义的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 }
}

onCompletedComponent类型的附加信号处理程序。使用方式为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
}

获取更多信息,请关注作者公众号:程序员练兵场
在这里插入图片描述

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值