Property Binding
对象的属性可以是一个静态值. 但是, 为了充分利用QML对动态对象行为的支持, 多数QML对象使用属性绑定.
属性绑定是QML的核心功能, 允许开发人员指定不同对象属性间关系. 属性依赖项的值发生改变时, 属性根据指定关系自动更新.
在后台, QML引擎检测属性的依赖项(即绑定表达式中的变量). 当检测到依赖项更改时, QML引擎根据指定关系自动更新属性值.
概述
创建属性绑定的方式: 为属性分配一个JavaScript表达式, 表达式的结果是属性的值. 简单来说, 绑定是对另一个属性的引用. 如下示例, 蓝色 Rectangle的高度绑定到父对象的高度:
Rectangle { width: 200; height: 200 Rectangle { width: 100 height: parent.height color: "blue" } }
无论父对象Rectangle何时变化, 蓝色Rectangle的高度自动更新为相同的值.
绑定可以是任何有效的JavaScript表达式或语句, 因为QML使用符合标准的JavaScript引擎. 绑定可以访问对象属性, 方法, 并可以使用内置的JavaScript对象, 如Date
和Math
. 下面代码是除上一个示例外的其他绑定方式:
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.width
和column.width
topRect.height
取决于column.height
bottomRect.color
取决于myTextInput.text.length
从语法上讲, 绑定可以是任意复杂的. 然而, 如果绑定过于复杂, 例如涉及多行或命令式循环, 则可能表明该绑定不仅仅用于描述属性关系. 复杂的绑定会降低代码的性能, 可读性和可维护性. 重新设计具有复杂绑定的组件可能是一个好主意, 或者至少将绑定分解为一个单独的函数.一般来说, 用户不应依赖绑定的评估顺序.
从JavaScript创建属性绑定
已绑定的属性根据需要自动更新. 但是, 如果之后给属性赋一个静态值, 则绑定将被删除.
如下所示, 最初, Rectangle 的 height
始终是 width
的两倍. 但是, 当按下空格键时, width*3
将作为静态值分配给 height
. 之后, 即使width
发生变化, height
也将保持固定在该值. 静态值的赋值将删除绑定.
import QtQuick 2.0 Rectangle { width: 100 height: width * 2 focus: true Keys.onSpacePressed: { height = width * 3 } }
如果上述代码的目的是给Rectangle赋一个固定高度, 并停止自动更新, 那么这不是一个问题. 但是, 如果仅仅想建立新的关系, 则必需将新的绑定表达式封装在Qt.binding()函数中:
import QtQuick 2.0 Rectangle { width: 100 height: width * 2 focus: true Keys.onSpacePressed: { height = Qt.binding(function() { return width * 3 }) } }
现在, 按下空格键后, Rectangle的高度始终是宽度的3倍.
使用 this
进行属性绑定
从JavaScript创建属性绑定时, this
关键字可用于引用接收绑定的对象, 这有助于解决属性名称的歧义.
例如, 下面的 Component.onCompleted
处理程序是在 Item的范围内定义的. 在此范围中, width
指的是 Item的 width, 而不是 Rectangle的 width. 若要将 Rectangle的 height
绑定到其自身的 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.