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对象, 如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创建属性绑定

已绑定的属性根据需要自动更新. 但是, 如果之后给属性赋一个静态值, 则绑定将被删除.

如下所示, 最初, Rectangleheight 始终是 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. 若要将 Rectangleheight 绑定到其自身的 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.