属性绑定

对象的属性可以分配一个静态值,这个值在未被明确分配新的值之前保持不变。然而,为了最大限度地利用 QML 及其内置对动态对象行为的支持,大多数 QML 对象都使用 属性绑定

属性绑定是 QML 的核心功能,允许开发者指定不同对象属性之间的关系。当一个属性的 依赖 值改变时,该属性将根据指定的关系自动更新。

在幕后,QML 引擎监视属性的依赖(即在绑定表达式中的变量)。当检测到变化时,QML 引擎会重新评估绑定表达式并将其结果应用到属性上。

概览

要创建属性绑定,需要将一个属性分配一个计算结果为所需值的 JavaScript 表达式。在最简单的形式中,绑定可能是指向另一个属性的引用。以下是一个示例,其中蓝色的 Rectangle 的高度绑定到其父元素的高度

Rectangle {
    width: 200; height: 200

    Rectangle {
        width: 100
        height: parent.height
        color: "blue"
    }
}

每当父矩形的高度发生变化时,蓝色矩形的高度将自动更新到相同的值。

绑定可以包含任何有效的 JavaScript 表达式或语句,因为 QML 使用了一个符合标准的 JavaScript 引擎。绑定可以访问对象属性、调用方法和使用内置的 JavaScript 对象,如 DateMath。以下是前一个示例的一些其他可能的绑定

height: parent.height / 2

height: Math.min(parent.width, parent.height)

height: parent.height > 100 ? parent.height : parent.height/2

height: {
    if (parent.height > 100)
        return parent.height
    else
        return parent.height / 2
}

height: someMethodThatReturnsHeight()

以下是一个涉及更多对象和类型的更复杂示例

Column {
    id: column
    width: 200
    height: 200

    Rectangle {
        id: topRect
        width: Math.max(bottomRect.width, parent.width/2)
        height: (parent.height / 3) + 10
        color: "yellow"

        TextInput {
            id: myTextInput
            text: "Hello QML!"
        }
    }

    Rectangle {
        id: bottomRect
        width: 100
        height: 50
        color: myTextInput.text.length <= 10 ? "red" : "blue"
    }
}

在上一个示例中,

  • topRect.width 依赖于 bottomRect.widthcolumn.width
  • topRect.height 依赖于 column.height
  • bottomRect.color 依赖于 myTextInput.text.length

在语法上,绑定可以是任意复杂的。但是,如果绑定过于复杂——如涉及多行或命令式循环——这可能表明绑定被用于描述属性关系之外的更多目的。复杂的绑定可能会降低代码的性能、可读性和可维护性。重新设计具有复杂绑定的组件,或者至少将绑定分解到独立的函数中,可能是一个好主意。作为一个一般规则,用户不应依赖于绑定评估的顺序。

从 JavaScript 创建属性绑定

具有绑定的属性将根据需要自动更新。但是,如果该属性稍后被 JavaScript 语句分配了静态值,则绑定将被移除。

例如,下面的矩形最初确保其高度始终是其宽度的两倍。然而,当按下空格键时,width*3的当前值将被作为静态值分配给高度。之后,高度将保持在这个值上固定,即使宽度发生变化。分配静态值会移除绑定。

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = width * 3
    }
}

如果意图是给矩形一个固定的高度并停止自动更新,那么这没问题。然而,如果意图是建立宽度高度之间的新关系,那么新的绑定表达式必须包裹在Qt.binding()函数中

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = Qt.binding(function() { return width * 3 })
    }
}

现在,按下空格键后,矩形的高度将继续自动更新,始终是宽度的三倍。

调试绑定覆盖

在QML应用中,意外使用JavaScript语句中的静态值覆盖绑定是常见的错误原因。为了帮助开发者追踪这类问题,QML引擎能够在由于命令式赋值而丢失绑定时发出消息。

为了生成这样的消息,您需要启用qt.qml.binding.removal记录类别的信息输出,例如通过调用

QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));

有关启用日志类别的输出的更多信息,请参阅QLoggingCategory文档。

请注意,在某些情况下覆盖绑定是完全合理的。QML引擎生成的任何消息都应被视为诊断工具,而不一定是进一步调查之前的问题的证据。

使用this与属性绑定

从JavaScript创建属性绑定时,可以使用this关键字来指代接收绑定的对象。这对于解决属性名歧义是有帮助的。

例如,下面的Component.onCompleted处理程序是在Item的作用域中定义的。在这个作用域内,width指的是Item的宽度,而不是矩形的宽度。为了将矩形高度绑定到其自身的width,绑定表达式必须显式地引用this.width(或者也可以使用rect.width

Item {
    width: 500
    height: 500

    Rectangle {
        id: rect
        width: 100
        color: "yellow"
    }

    Component.onCompleted: {
        rect.height = Qt.binding(function() { return this.width * 2 })
        console.log("rect.height = " + rect.height) // prints 200, not 1000
    }
}

注意:在属性绑定之外,this的值是没有定义的。有关详细信息,请参阅JavaScript Environment Restrictions

另请参阅使用锚定位.

© 2024 Qt公司股份公司。此处包含的文档贡献的版权归其各自所有者。本提供的文档是根据自由软件基金会发布的GNU自由文档许可证版本1.3的条款许可的。Qt和相应的商标是芬兰及其它国家的Qt公司注册的商标。所有其他商标均为各自所有者的财产。