aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
blob: a5ad6af4a2aac9e88f16ed1c0eaa4bb0066be1e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
\page qtqml-syntax-propertybinding.html
\title Property Binding
\brief 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 \e {property bindings}.

Property bindings are a core feature of QML that lets developers specify relationships
between different object properties. When a property's \e 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.

\section1 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 \l Rectangle's height
is bound to the height of its parent:

\qml
Rectangle {
    width: 200; height: 200

    Rectangle {
        width: 100
        height: parent.height
        color: "blue"
    }
}
\endqml

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 \c Date and \c Math.
Below are other possible bindings for the previous example:

\code
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()
\endcode

Below is a more complex example involving more objects and types:

\qml
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"
    }
}
\endqml

In the previous example,
\list
\li \c topRect.width depends on \c bottomRect.width and \c column.width
\li \c topRect.height depends on \c column.height
\li \c bottomRect.color depends on \c myTextInput.text.length
\endlist

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.


\target qml-javascript-assignment
\section1 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 \l Rectangle below initially ensures that its \c height is always
twice its \c width. However, when the space key is pressed, the current value
of \c {width*3} will be assigned to \c height as a \e static value.  After that,
\e {the \c height will remain fixed at this value, even if the \c width changes}.
The assignment of the static value removes the binding.

\qml
import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = width * 3
    }
}
\endqml

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 \c width and \c height, then the new binding
expression must be wrapped in the Qt.binding() function instead:

\qml
import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = Qt.binding(function() { return width * 3 })
    }
}
\endqml

Now, after the space key is pressed, the rectangle's height will continue
auto-updating to always be three times its width.

\section3 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 \c{qt.qml.binding.removal} logging category, for instance by calling:

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

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.

\section2 Using \c this with Property Binding

When creating a property binding from JavaScript, the \c 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 \c Component.onCompleted handler below is defined within the
scope of the \l Item. In this scope, \c width refers to the \l Item's width, not
the \l Rectangle's width. To bind the \l Rectangle's \c height to its own \c width,
the binding expression must explicitly refer to \c this.width (or alternatively,
\c{rect.width}):

\qml
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
    }
}
\endqml

\note The value of \c this is not defined outside of property bindings.
See \l {JavaScript Environment Restrictions} for details.
*/