Property Binding

binding object properties

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.

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.

Behind the scenes, the QML engine monitors the property’s dependencies (that is, the variables in the binding expression). When a change is detected, the QML engine re-evaluates the binding expression and applies the new result to the property.

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:

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

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:

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:

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

In addition, any properties referenced within a JavaScript function that is itself used as a binding will be re-evaluated. For example, in the snippet below, whenever the enabled property of the Rectangle changes, the bindings for the x and y properties will be re-evaluated:

Rectangle {
    x: rectPosition()
    y: rectPosition()
    width: 200
    height: 200
    color: "lightblue"

    function rectPosition() {
        return enabled ? 0 : 100
    }
}

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. As a general rule, users should not rely on the evaluation order of bindings.

Creating Property Bindings from 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.

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, theheightwill remain fixed at this value, even if thewidthchanges. The assignment of the static value removes the binding.

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:

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.

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:

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

Please refer to the QLoggingCategory documentation for more information about enabling output from logging categories.

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.

Using `` this``

with 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.

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):

Note

The value of this is not defined outside of property bindings. See JavaScript Environment Restrictions for details.

See also

Positioning with Anchors