可以为属性分配一个静态值。然而,为了充分利用 QML 及其对动态对象行为的内置支持,大多数 QML 对象使用 property bindings。这是 QML 的一个核心特性,它可以指定属性间的关系。当一个属性值变化时,另一个属性值也会自动更新。

3.1 概述

为属性分配一个 JavaScript 表达式来创建属性绑定。示例:

  1. Rectangle {
  2. width: 200; height: 200
  3. Rectangle {
  4. width: 100
  5. height: parent.height //父矩形的高度变化时,蓝色矩形的高度也会变
  6. color: "blue"
  7. }
  8. }

绑定可以访问对象属性、调用方法并使用内置的 JavaScript 对象,例如 Date 和 Math:

  1. //简单示例
  2. height: parent.height / 2
  3. height: Math.min(parent.width, parent.height)
  4. height: parent.height > 100 ? parent.height : parent.height/2
  5. height: {
  6. if (parent.height > 100)
  7. return parent.height
  8. else
  9. return parent.height / 2
  10. }
  11. height: someMethodThatReturnsHeight()
  12. //更复杂示例
  13. Column {
  14. id: column
  15. width: 200
  16. height: 200
  17. Rectangle {
  18. id: topRect
  19. width: Math.max(bottomRect.width, parent.width/2) //topRect.width 取决于 bottomRect.width 和 column.width
  20. height: (parent.height / 3) + 10 //topRect.height 取决于 column.height
  21. color: "yellow"
  22. TextInput {
  23. id: myTextInput
  24. text: "Hello QML!"
  25. }
  26. }
  27. Rectangle {
  28. id: bottomRect
  29. width: 100
  30. height: 50
  31. color: myTextInput.text.length <= 10 ? "red" : "blue" //bottomRect.color 取决于 myTextInput.text.length
  32. }
  33. }

如果绑定过于复杂,如涉及多行或命令式循环,则可能表明绑定不仅仅用于描述属性关系。复杂的绑定会降低代码性能、可读性和可维护性。 重新设计组件可能是一个好主意,或者至少将绑定分解为一个单独的函数。作为一般规则,用户不应依赖绑定的评估顺序。

3.2 使用 JavaScript 创建属性绑定

如果为属性设置了一个静态值,则之前的绑定将被删除。例如:

  1. import QtQuick 2.0
  2. Rectangle {
  3. width: 100
  4. height: width * 2
  5. focus: true
  6. Keys.onSpacePressed: {
  7. height = width * 3
  8. }
  9. }

如果为属性设置新的绑定,则必须将新表达式包装在 Qt.binding() 函数中:

  1. import QtQuick 2.0
  2. Rectangle {
  3. width: 100
  4. height: width * 2
  5. focus: true
  6. Keys.onSpacePressed: {
  7. height = Qt.binding(function() { return width * 3 })
  8. }
  9. }

3.2.1 调试覆盖绑定

QML 程序中的常见错误是意外地用 JavaScript 语句中的静态值覆盖了绑定。QML 引擎能够在由于命令式赋值而丢失绑定时发出消息。为了生成此类消息,您需要为 qt.qml.binding.removal日志记录类别启用信息输出,例如通过调用:

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

更多信息,请参阅 QLoggingCategory 文档。请注意,在某些情况下覆盖绑定是完全合理的。QML 引擎生成的任何消息都应被视为诊断帮助,而不一定是未经进一步调查的问题的证据。

3.2.2 使用 this

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

例如,下面的 Component.onCompleted 处理程序是在 Item 的范围内定义的。在此范围内,width 指的是 Item 的宽度,而不是 Rectangle 的宽度。要将 Rectangle 的高度绑定到它自己的宽度,绑定表达式必须明确引用 this.widthrect.width

  1. Item {
  2. width: 500
  3. height: 500
  4. Rectangle {
  5. id: rect
  6. width: 100
  7. color: "yellow"
  8. }
  9. Component.onCompleted: {
  10. rect.height = Qt.binding(function() { return this.width * 2 })
  11. console.log("rect.height = " + rect.height) // prints 200, not 1000
  12. }
  13. }

注意: this 的值不是在属性绑定之外定义的。更多信息,请参阅 JavaScript Environment Restrictions