属性绑定¶
绑定对象属性
对象的属性可以被赋予一个静态值,该值保持不变,直到显式赋予新值。然而,为了充分利用QML及其对动态对象行为的内置支持,大多数QML对象使用属性绑定。
属性绑定是QML的一个核心特性,它允许开发者指定不同对象属性之间的关系。当一个属性的依赖项值发生变化时,该属性会根据指定的关系自动更新。
在幕后,QML引擎监视属性的依赖关系(即绑定表达式中的变量)。当检测到变化时,QML引擎重新评估绑定表达式并将新结果应用于属性。
概述¶
要创建一个属性绑定,需要将一个属性赋值为一个JavaScript表达式,该表达式计算得出所需的值。最简单的绑定可能是对另一个属性的引用。以下面的例子为例,蓝色矩形的高度绑定到其父级的高度:
每当父矩形的高度发生变化时,蓝色矩形的高度会自动更新为相同的值。
绑定可以包含任何有效的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()
下面是一个涉及更多对象和类型的更复杂示例:
在前面的例子中,
topRect.width
依赖于bottomRect.width
和column.width
topRect.height
依赖于column.height
bottomRect.color
取决于myTextInput.text.length
此外,任何在JavaScript函数中引用的属性,如果该函数本身被用作绑定,将会被重新评估。例如,在下面的代码片段中,每当Rectangle
的enabled
属性发生变化时,x
和y
属性的绑定将会被重新评估:
Rectangle { x: rectPosition() y: rectPosition() width: 200 height: 200 color: "lightblue" function rectPosition() { return enabled ? 0 : 100 } }
从语法上讲,绑定允许具有任意复杂性。然而,如果绑定过于复杂——例如涉及多行或命令式循环——这可能表明绑定被用于不仅仅是描述属性关系。复杂的绑定可能会降低代码的性能、可读性和可维护性。重新设计具有复杂绑定的组件,或者至少将绑定提取到一个单独的函数中,可能是一个好主意。作为一般规则,用户不应依赖绑定的评估顺序。
从JavaScript创建属性绑定¶
具有绑定的属性会根据需要自动更新。然而,如果该属性后来通过JavaScript语句分配了一个静态值,绑定将被移除。
例如,下面的矩形最初确保其height
始终是其width
的两倍。然而,当按下空格键时,width*3
的当前值将被分配给height
作为一个静态值。之后,即使width发生变化,height也将保持固定在这个值。静态值的分配会移除绑定。
如果目的是给矩形一个固定的高度并停止自动更新,那么这不是问题。然而,如果目的是在width
和height
之间建立新的关系,那么新的绑定表达式必须包装在Qt.binding()函数中:
现在,按下空格键后,矩形的高度将继续自动更新,始终保持其宽度的三倍。
调试绑定的覆盖¶
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的宽度,而不是Rectangle的宽度。要将Rectangle的height
绑定到它自己的width
,绑定表达式必须明确引用this.width
(或者,rect.width
):