Translated from the original page(Qt Documentation>Qt5.11Qt QML>Property Binding)

Property Binding

属性绑定

An object’s property can be assigned a static value which stays constant until it is explicitly assigned a new value. However, to make the fullest use of QML and its built-in support for dynamic object behaviors, most QML objects use property bindings.

可以为一个对象的属性分配一个静态值,该值在分配明确的新值之前保持不变。 但是,为了充分利用QML及其对动态对象行为的内置支持,大多数QML对象都使用属性绑定

Property bindings are a core feature of QML that lets developers specify relationships between different object properties. When a property’s dependencies change in value, the property is automatically updated according to the specified relationship.

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

Overview

概述

To create a property binding, a property is assigned a JavaScript expression that evaluates to the desired value. At its simplest, a binding may be a reference to another property. Take the following example, where the blue Rectangle’s height is bound to the height of its parent:

去创建一个属性绑定时,该属性会被分配一个Javascript表达式,该表达式的计算结果即是要分配的值。最简单的是,一个绑定肯是另一个属性的引用。通过下面的例子,一个蓝色Rectangle的高度被绑定到父类的高度:

1
2
3
4
5
6
7
8
9
Rectangle {
width: 200; height: 200

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

Whenever the height of the parent rectangle changes, the height of the blue rectangle automatically updates to be of the same value.

只要父类rectangle的高度变化,该蓝色Rectangle的高度将会自动更新为相同的值。

A binding can contain any valid JavaScript expression or statement, as QML uses a standards compliant JavaScript engine. Bindings can access object properties, call methods and use built-in JavaScript objects such as Date and Math. Below are other possible bindings for the previous example:

因为QML使用符合标准的JavaScript引擎,绑定可以包含任何一个有效的JavaScript表达式或者声明。绑定可以访问对象属性,调用方法并使用诸如Date和Math的内置JavaScript对象。以下是前一个例子的其他可能的绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()

Below is a more complex example involving more objects and types:
以下是包含更多对象和类型的更复杂的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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"
}
}

In the previous example,

topRect.width depends on bottomRect.width and column.width
topRect.height depends on column.height
bottomRect.color depends on myTextInput.text.length

在前一个例子中,

topRect.width 取决于 bottomRect.width 和 column.width
topRect.height 取决于 column.height
bottomRect.color取决于 myTextInput.text.length

Syntactically, bindings are allowed to be of arbitrary complexity. However, if a binding is overly complex - such as involving multiple lines, or imperative loops - it could indicate that the binding is being used for more than describing property relationships. Complex bindings can reduce code performance, readability, and maintainability. It may be a good idea to redesign components that have complex bindings, or at least factor the binding out into a separate function.

从语法上讲,允许绑定具有任意的复杂性。但是,如果一个绑定过于复杂--比如包含多行,或强制性循环-则表明绑定可能不仅仅用于描述属性关系。复杂的绑定会降低代码的性能,可读性和可维护性。重定义具有复杂绑定的空间,或至少将绑定分解为单独的函数可能会更好。

Creating Property Bindings from JavaScript

创建基于JavaScript的属性绑定

A property with a binding is automatically updated as necessary. However, if the property is later assigned a static value from a JavaScript statement, the binding will be removed.
具有绑定的属性会根据需要自动更新。但是,如果后来通过从JavaScript语句为属性分配了静态值,则将删除绑定。

For example, the Rectangle below initially ensures that its height is always twice its width. However, when the space key is pressed, the current value of width*3 will be assigned to height as a static value. After that, the height will remain fixed at this value, even if the width changes. The assignment of the static value removes the binding.

例如,下面的长方形(Rectangle)最初确定了其高度(height)永远是其宽度(width)的两倍。但是,当按下空格键时,当前width*3的值将被赋值给高度作为一个静态值(常量)。之后,即使宽度改变,高度也将固定保持在这个值。静态值的赋值解除了绑定。

1
2
3
4
5
6
7
8
9
10
11
import QtQuick 2.0

Rectangle {
width: 100
height: width * 2

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

If the intention is to give the rectangle a fixed height and stop automatic updates, then this is not a problem. However, if the intention is to establish a new relationship between width and height, then the new binding expression must be wrapped in the Qt.binding() function instead:
如果打算给矩形一个固定的高度并停止自动更新,那么这不是问题。 但是,如果打算在宽度和高度之间建立新的关系,那么新的绑定表达式必须包含在Qt.binding()函数中:

1
2
3
4
5
6
7
8
9
10
11
import QtQuick 2.0

Rectangle {
width: 100
height: width * 2

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

Now, after the space key is pressed, the rectangle’s height will continue auto-updating to always be three times its width.
现在,按下空格键后,矩形的高度将继续自动更新,始终为宽度的三倍。

Debugging overwriting of bindings

调试覆盖绑定

A common cause of bugs in QML applications is accidentally overwriting bindings with static values from JavaScript statements. To help developers track down problems of this kind, the QML engine is able to emit messages whenever a binding is lost due to imperative assignments.
QML应用程序中的错误的常见原因是不慎地使用JavaScript语句中的静态值覆盖绑定。为了去帮开发者追踪这类问题,QML引擎会在绑定因为强制赋值而丢失时发出信息。

In order to generate such messages, you need to enable the informational output for the qt.qml.binding.removal logging category, for instance by calling:
为了生成此类消息,您需要为qt.qml.binding.removal日志记录类别启用信息输出,例如通过调用:

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

Please refer to the QLoggingCategory documentation for more information about enabling output from logging categories.
有关从日志记录类别启用输出的详细信息,请参阅QLoggingCategory文档。

Note that is perfectly reasonable in some circumstances to overwrite bindings. Any message generated by the QML engine should be treated as a diagnostic aid, and not necessarily as evidence of a problem without further investigation.

请注意,在一些情况下重写绑定是完全合理的。通过QML生成的任何信息应该被视作辅助的诊断,在没有进一步调查的情况下,不能视作是问题的必要证据。

Using this with Property Binding

使用Property Binding

When creating a property binding from JavaScript, the this keyword can be used to refer to the object which receives the binding. This is helpful for resolving ambiguities with property names.
当通过JavaScript创建属性绑定的时候,this关键字可用于引用接收绑定的对象。这有助于解决属性名称的歧义问题。

For example, the Component.onCompleted handler below is defined within the scope of the Item. In this scope, width refers to the Item’s width, not the Rectangle’s width. To bind the Rectangle’s height to its own width, the binding expression must explicitly refer to this.width (or alternatively, rect.width):

例如,下面的Component.onCompleted处理程序在Item的范围内被定义。在此范围中,width指的是Item的宽度,而不是Rectangle的宽度。 要将Rectangle的高度绑定到自己的宽度,绑定表达式必须显式引用this.width(或者rect.width):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
}
}

Note: The value of this is not defined outside of property bindings. See JavaScript Environment Restrictions for details.
注意:此值未在属性绑定之外定义。 有关详细信息,请参阅JavaScript环境限制