summaryrefslogtreecommitdiffhomepage
path: root/qml.html.markdown
blob: 78e94d6634f64f558308f1097fbf717b6e8d6922 (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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
---
language: QML
contributors:
    - ["Furkan Uzumcu", "https://zmc.space/"]
filename: learnqml.qml
lang: en-us
---

```qml
// This is a completely valid QML file that you can run using `qmlscene` if you copy the contents
// into a *.qml file.
// Comments start with double forward slashes.
/* Or you
   can have
   multi line
   comments
 */

// Import statement syntax is
// import ${MODULE_NAME} [${VERSION_NUMBER}] [as ${QUALIFIER}]
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QQC
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1

// Each QML document can contain only one top level type
Window {
    // Each object has a special and optional `id` attribute that can be used to refer to the
    // declared objects. An `id` has to be unique in the same document.
    id: root
    width: 400
    height: 600
    title: "Learn QML in Y Minutes"

    Item {
        // Every object that can be declared inherits from QObject and contains at
        // least one property, which is `objectName`. All the other properties are
        // added by extending `QObject` type. This is an `Item` type and it contains
        // the additional `width` and `height` properties and more.
        objectName: "My Item"
        // `id`s in the same document can be used anywhere in the same file.
        // You cannot access an `id` from a different file.
        width: root.width
    }

    // Signals are used to communicate that a certain event happened.
    // Some types have built-in signals
    Timer {
        id: timer
        interval: 500
        onTriggered: {
            console.log("Timer triggered!")
        }
    }

    QtObject {
        id: objSignals
        // You can also declare your own signals.
        signal clicked()
        // Signals can also have arguments.
        signal mousePositionChanged(int x, int y)
        // The way to react to a signal emission is by adding signal handlers to
        // the immediate object that the signal belongs to.
        onClicked: () => {
            // Do stuff here.
            console.log("objSignals.clicked() signal is emitted.")
        }
        // Signal handlers must explicitly declare the arguments.
        onMousePositionChanged: (x, y) => {
            // Do stuff here.
            console.log("objSignals.mousePositionChanged() signal is emitted. x=", x, "y=", y)
        }
    }

    // If you want to declare signal handlers for other objects, you can use
    // `Connections`.
    Connections {
        target: objSignals

        // You can then declare functions with the same name as the signal
        // handler.
        function onClicked() {
            console.log("objSignals.clicked() signal is handled from Connections.")
        }
    }

    Item {
        visible: false

        // An object can support having child objects. You can add child objects
        // by declaring types as follows:
        Rectangle {
            width: 16
            height: 16
            color: "red"
        }
    }

    Item {
        id: objProperties
        // You can also declare your own properties.
        // Syntax for declaring is
        // [default] [required] [readonly] property ${TYPE} ${NAME}
        property color nextColor
        // Read only properties have to be initialized when declared.
        readonly property color defaultColor: "red"
        // Required properties have to be initialized where the reusable type is
        // used.
        required property color initialColor

        // NOTE: Although the initial assignment can be done in the same file,
        // it is not often the use case.
        initialColor: "green"

        // Properties are type safe and a property can only be assigned a value
        // that matches the property type.
        // property int volume: "four" // ERROR!

        Item {
            // You can create alias properties that hold a reference to another
            // property.

            property alias parentNextColor: objProperties.nextColor

            // Assignments to alias properties alter the property that it holds
            // a reference to.
            parentNextColor: "blue" // Changes objProperties.nextColor
            // Since `parentNextColor` is an alias to `nextColor`, any changes
            // to `nextColor` will also be reflected to `parentNextColor`.
        }
    }

    Item {
        // Property assignment values can either be static or binding
        // expressions.
        // Static value
        property int radius: 32
        // Binding expressions describe a property's relationship to other
        // properties. When the value of `radius` changes, the expression here
        // will be re-evaluated.
        property int diameter: radius * 2

        onDiameterChanged: {
            console.log("onDiameterChanged:", diameter)
        }
    }

    ListView {
        // Attached properties and signal handlers provide a way to extend an
        // existing object and provide more information that is otherwise not
        // immediately available.
        width: 100
        height: 30
        model: 3
        delegate: Rectangle {
            // ListView provides an attached property for its children that can
            // be used to access more information.
            color: ListView.isCurrentItem ? "green" : "red"
        }
        // Attached types can also have signal handlers.
        // `Component` is attached to every type that's available in QML.
        Component.onCompleted: {
            console.log("This signal handler is called after object is created.")
        }
    }

    Rectangle {
        // Since this rectangle is not created by the ListView, the attached
        // type is not avaiable.
        color: ListView.isCurrentItem ? "green" : "red"
    }

    QtObject {
        id: calculator

        // Objects can also declare methods. Function declarations can annotate
        // the arguments, or have no arguments at all.
        function add(a: int, b: int): int {
            // Semicolon at the end of a line is optional.
            return a + b
        }

        function multiply(a: real, b: real): real {
            return a * b;
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: (mouse) => {
            console.log("2 + 2 =", calculator.add(2, 2))
        }
    }

    Item {
        width: 100
        // Methods can also be used as binding expressions. When `width`
        // changes, the binding expression will evaluate and call `multiply`.
        height: calculator.multiply(width, 0.5)
        opacity: calculateOpacity()

        function calculateOpacity() {
            // If the function declaration contains references to other
            // properties, changes to those properties also trigger a binding
            // evaluation.
            return height < 50 ? 0.5 : 1
        }
    }

    // Each QML file that starts with an upper case name declares a re-usable
    // component, e.g "RedRectangle.qml".
    // In addition, reusable components can be declared in-line.
    component RedRectangle: Rectangle {
        color: "red"
    }

    // This inline component can then be used in the same file, or in other
    // files by prefixing the type name with the file name that it belongs to.
    //
    // ${FILE_NAME}.RedRectangle { }
    // or
    RedRectangle {
    }

    // QML also supports enumeration declarations.
    component MyText: Text {
        enum TextType {
            Normal,
            Heading
        }

        // Enum types are assigned to integer properties.
        property int textType: MyText.TextType.Normal

        font.bold: textType == MyText.TextType.Heading
        font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
    }

    // ----- Interactive Area

    QQC.ScrollView {
        anchors.fill: parent
        contentWidth: container.implicitWidth
        contentHeight: container.implicitHeight

        Column {
            id: container
            spacing: 6

            Row {
                spacing: 2

                QQC.Label {
                    width: 200
                    anchors.verticalCenter: parent.verticalCenter
                    text: "Click to start the timer.\nCheck the logs!"
                    wrapMode: QQC.Label.WordWrap
                }

                QQC.Button {
                    text: timer.running ? "Timer Running" : "Start Timer"
                    onClicked: {
                        timer.start()
                    }
                }
            }

            Row {
                spacing: 2

                QQC.Label {
                    width: 200
                    anchors.verticalCenter: parent.verticalCenter
                    text: "Click to emit objSignals.clicked() signal"
                    wrapMode: QQC.Label.WordWrap
                }

                QQC.Button {
                    property int emissionCount: 0

                    text: "Emitted " + emissionCount + " times."
                    onClicked: {
                        objSignals.clicked()
                        emissionCount++
                    }
                }
            }

            Row {
                spacing: 2

                QQC.Label {
                    width: 200
                    anchors.verticalCenter: parent.verticalCenter
                    text: "Click to emit objSignals.mousePositionChanged() signal"
                    wrapMode: QQC.Label.WordWrap
                }

                QQC.Button {
                    property int emissionCount: 0

                    text: "Emitted " + emissionCount + " times."
                    onClicked: {
                        objSignals.mousePositionChanged(32, 32)
                        emissionCount++
                    }
                }
            }

            Rectangle {
                width: 200
                height: 80
                color: objProperties.nextColor

                QQC.Label {
                    width: 200
                    anchors.verticalCenter: parent.verticalCenter
                    text: "Click to change nextColor property."
                    wrapMode: QQC.Label.WordWrap
                }

                TapHandler {
                    onTapped: {
                        colorDialog.open()
                    }
                }

                ColorDialog {
                    id: colorDialog
                    currentColor: objProperties.initialColor
                    onColorChanged: {
                        objProperties.nextColor = color

                    }
                }
            }

            Row {
                spacing: 2

                Rectangle {
                    width: 200
                    height: 80
                    color: "red"
                    radius: radiusSlider.value

                    QQC.Label {
                        width: parent.width
                        anchors.centerIn: parent
                        text: "Use slider to change radius"
                        wrapMode: QQC.Label.WordWrap
                        horizontalAlignment: Qt.AlignHCenter
                    }
                }

                QQC.Slider {
                    id: radiusSlider
                    width: 100
                    anchors.verticalCenter: parent.verticalCenter
                    from: 0
                    to: 80
                }
            }
        }
    }
}
```