A property binding exists between two properties ‘a’ and ‘b’, written as ‘a: b’ such that the value of ‘a’ updates whenever ‘b’ updates. Typical use-cases are: controlling element size, controlling position of an element through anchors, dynamically changing text or images, controlling element colors or controlling button states.
In its simplest form, ‘a’ – once bound to ‘b’ – maintains the same value as ‘b’, for the lifetime of the property binding. In its more advanced form, ‘a’ is bound to an arbitrary JavaScript expression that makes use of ‘b’, like so: ‘a: b + 1′.
It is also possible to bind ‘a’ to more than one property: ‘a: b * c + 1′. Here, the expression will be evaluated whenever ‘b’ or ‘c’ changes.
The following table shows the value of ‘a’, depending on how ‘b’ and ‘c’ change their values over time.
a:b*c+1 a b c
initial state 1 0 0
b = 1 1 1 0
c = 2 3 1 2
b = -3 -5 -3 2
The possibilities for property bindings seem unlimited, and indeed, they can also be established between properties of different type. Consider a color property ‘c’ being bound to an enumeration type ‘e’. The naive approach, ‘c: e’, will not work. But ‘e’ can be handed to a conversion function, done with some JavaScript:
function toColor(e) { switch(e) { case highlighted: return "blue"; case inactive: return "white"; default: return "black"; } }
Now the property binding can be written as:
c: toColor(e)
and it will work as expected. ‘c’ will update correctly even if toColor internally depends on another property but e, but such hidden dependencies are best avoided.
Never assign to bound properties. Properties are either free or bound (to other properties). Assigning a value explicitly is OK, as long as the property is free. Once it becomes bound, any new assignment would remove the previous property binding. This can be a source of bugs and as such, should be avoided.
Use property bindings over explicit state handling. Whenever state handling logic is used in QML, there is a more robust solution that relies on property binding instead and will achieve the same result. Hide the state handling behind new properties. Once the state handling logic grows, property bindings tend to scale better in terms of complexity.
Marking an item as active, through explicit state handling.
import QtQuick 1.0 // Becomes active once clicked, deactivates with next click. Rectangle { id: canvas anchors.fill: parent color: "green" MouseArea { anchors.fill: parent onClicked: { canvas.state == "activated" ? canvas.state = "" : canvas.state = "activated" } } states: [ State { name: "activated" PropertyChanges { target: canvas color: "red" } } ] }
Marking an item as active, through a new custom property bound to item’s color property.
import QtQuick 1.0 // Becomes active once clicked, deactivates with next click. Rectangle { id: canvas anchors.fill: parent property bool activated: false color: activated ? "red" : "green" MouseArea { anchors.fill: parent onClicked: { canvas.activated = !canvas.activated } } }
The flexibility and ease of use explains why property bindings are used pervasively in programming with QML language. Elements should be designed as being purely dependent on their properties whenever it comes to dynamic changes. Combined with property bindings, these elements will work in a “fire-and-forget” fashion, meaning that after the initial setup, they will just keep working correctly, regardless of other considerations. This makes it possible to deal with more complex UI’s but just as importantly, it also keeps the code clean and reduces the risk of introducing bugs.
Property bindings don’t come for free though and under certain conditions the performance impact can become noticeable. This, however, will be material for a future article in this series.
Source QtExperts