1// This is a completely valid QML file that you can run using `qmlscene` if you copy the contents
2// into a *.qml file.
3// Comments start with double forward slashes.
4/* Or you
5 can have
6 multi line
7 comments
8 */
9
10// Import statement syntax is
11// import ${MODULE_NAME} [${VERSION_NUMBER}] [as ${QUALIFIER}]
12import QtQuick 2.15
13import QtQuick.Window 2.15
14import QtQuick.Controls 2.15 as QQC
15import QtQuick.Layouts 1.15
16import Qt.labs.platform 1.1
17
18// Each QML document can contain only one top level type
19Window {
20 // Each object has a special and optional `id` attribute that can be used to refer to the
21 // declared objects. An `id` has to be unique in the same document.
22 id: root
23 width: 400
24 height: 600
25 title: "Learn QML in Y Minutes"
26
27 Item {
28 // Every object that can be declared inherits from QObject and contains at
29 // least one property, which is `objectName`. All the other properties are
30 // added by extending `QObject` type. This is an `Item` type and it contains
31 // the additional `width` and `height` properties and more.
32 objectName: "My Item"
33 // `id`s in the same document can be used anywhere in the same file.
34 // You cannot access an `id` from a different file.
35 width: root.width
36 }
37
38 // Signals are used to communicate that a certain event happened.
39 // Some types have built-in signals
40 Timer {
41 id: timer
42 interval: 500
43 onTriggered: {
44 console.log("Timer triggered!")
45 }
46 }
47
48 QtObject {
49 id: objSignals
50 // You can also declare your own signals.
51 signal clicked()
52 // Signals can also have arguments.
53 signal mousePositionChanged(int x, int y)
54 // The way to react to a signal emission is by adding signal handlers to
55 // the immediate object that the signal belongs to.
56 onClicked: () => {
57 // Do stuff here.
58 console.log("objSignals.clicked() signal is emitted.")
59 }
60 // Signal handlers must explicitly declare the arguments.
61 onMousePositionChanged: (x, y) => {
62 // Do stuff here.
63 console.log("objSignals.mousePositionChanged() signal is emitted. x=", x, "y=", y)
64 }
65 }
66
67 // If you want to declare signal handlers for other objects, you can use
68 // `Connections`.
69 Connections {
70 target: objSignals
71
72 // You can then declare functions with the same name as the signal
73 // handler.
74 function onClicked() {
75 console.log("objSignals.clicked() signal is handled from Connections.")
76 }
77 }
78
79 Item {
80 visible: false
81
82 // An object can support having child objects. You can add child objects
83 // by declaring types as follows:
84 Rectangle {
85 width: 16
86 height: 16
87 color: "red"
88 }
89 }
90
91 Item {
92 id: objProperties
93 // You can also declare your own properties.
94 // Syntax for declaring is
95 // [default] [required] [readonly] property ${TYPE} ${NAME}
96 property color nextColor
97 // Read only properties have to be initialized when declared.
98 readonly property color defaultColor: "red"
99 // Required properties have to be initialized where the reusable type is
100 // used.
101 required property color initialColor
102
103 // NOTE: Although the initial assignment can be done in the same file,
104 // it is not often the use case.
105 initialColor: "green"
106
107 // Properties are type safe and a property can only be assigned a value
108 // that matches the property type.
109 // property int volume: "four" // ERROR!
110
111 Item {
112 // You can create alias properties that hold a reference to another
113 // property.
114
115 property alias parentNextColor: objProperties.nextColor
116
117 // Assignments to alias properties alter the property that it holds
118 // a reference to.
119 parentNextColor: "blue" // Changes objProperties.nextColor
120 // Since `parentNextColor` is an alias to `nextColor`, any changes
121 // to `nextColor` will also be reflected to `parentNextColor`.
122 }
123 }
124
125 Item {
126 // Property assignment values can either be static or binding
127 // expressions.
128 // Static value
129 property int radius: 32
130 // Binding expressions describe a property's relationship to other
131 // properties. When the value of `radius` changes, the expression here
132 // will be re-evaluated.
133 property int diameter: radius * 2
134
135 onDiameterChanged: {
136 console.log("onDiameterChanged:", diameter)
137 }
138 }
139
140 ListView {
141 // Attached properties and signal handlers provide a way to extend an
142 // existing object and provide more information that is otherwise not
143 // immediately available.
144 width: 100
145 height: 30
146 model: 3
147 delegate: Rectangle {
148 // ListView provides an attached property for its children that can
149 // be used to access more information.
150 color: ListView.isCurrentItem ? "green" : "red"
151 }
152 // Attached types can also have signal handlers.
153 // `Component` is attached to every type that's available in QML.
154 Component.onCompleted: {
155 console.log("This signal handler is called after object is created.")
156 }
157 }
158
159 Rectangle {
160 // Since this rectangle is not created by the ListView, the attached
161 // type is not available.
162 color: ListView.isCurrentItem ? "green" : "red"
163 }
164
165 QtObject {
166 id: calculator
167
168 // Objects can also declare methods. Function declarations can annotate
169 // the arguments, or have no arguments at all.
170 function add(a: int, b: int): int {
171 // Semicolon at the end of a line is optional.
172 return a + b
173 }
174
175 function multiply(a: real, b: real): real {
176 return a * b;
177 }
178 }
179
180 MouseArea {
181 anchors.fill: parent
182 onClicked: (mouse) => {
183 console.log("2 + 2 =", calculator.add(2, 2))
184 }
185 }
186
187 Item {
188 width: 100
189 // Methods can also be used as binding expressions. When `width`
190 // changes, the binding expression will evaluate and call `multiply`.
191 height: calculator.multiply(width, 0.5)
192 opacity: calculateOpacity()
193
194 function calculateOpacity() {
195 // If the function declaration contains references to other
196 // properties, changes to those properties also trigger a binding
197 // evaluation.
198 return height < 50 ? 0.5 : 1
199 }
200 }
201
202 // Each QML file that starts with an upper case name declares a re-usable
203 // component, e.g "RedRectangle.qml".
204 // In addition, reusable components can be declared in-line.
205 component RedRectangle: Rectangle {
206 color: "red"
207 }
208
209 // This inline component can then be used in the same file, or in other
210 // files by prefixing the type name with the file name that it belongs to.
211 //
212 // ${FILE_NAME}.RedRectangle { }
213 // or
214 RedRectangle {
215 }
216
217 // QML also supports enumeration declarations.
218 component MyText: Text {
219 enum TextType {
220 Normal,
221 Heading
222 }
223
224 // Enum types are assigned to integer properties.
225 property int textType: MyText.TextType.Normal
226
227 font.bold: textType == MyText.TextType.Heading
228 font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
229 }
230
231 // ----- Interactive Area
232
233 QQC.ScrollView {
234 anchors.fill: parent
235 contentWidth: container.implicitWidth
236 contentHeight: container.implicitHeight
237
238 Column {
239 id: container
240 spacing: 6
241
242 Row {
243 spacing: 2
244
245 QQC.Label {
246 width: 200
247 anchors.verticalCenter: parent.verticalCenter
248 text: "Click to start the timer.\nCheck the logs!"
249 wrapMode: QQC.Label.WordWrap
250 }
251
252 QQC.Button {
253 text: timer.running ? "Timer Running" : "Start Timer"
254 onClicked: {
255 timer.start()
256 }
257 }
258 }
259
260 Row {
261 spacing: 2
262
263 QQC.Label {
264 width: 200
265 anchors.verticalCenter: parent.verticalCenter
266 text: "Click to emit objSignals.clicked() signal"
267 wrapMode: QQC.Label.WordWrap
268 }
269
270 QQC.Button {
271 property int emissionCount: 0
272
273 text: "Emitted " + emissionCount + " times."
274 onClicked: {
275 objSignals.clicked()
276 emissionCount++
277 }
278 }
279 }
280
281 Row {
282 spacing: 2
283
284 QQC.Label {
285 width: 200
286 anchors.verticalCenter: parent.verticalCenter
287 text: "Click to emit objSignals.mousePositionChanged() signal"
288 wrapMode: QQC.Label.WordWrap
289 }
290
291 QQC.Button {
292 property int emissionCount: 0
293
294 text: "Emitted " + emissionCount + " times."
295 onClicked: {
296 objSignals.mousePositionChanged(32, 32)
297 emissionCount++
298 }
299 }
300 }
301
302 Rectangle {
303 width: 200
304 height: 80
305 color: objProperties.nextColor
306
307 QQC.Label {
308 width: 200
309 anchors.verticalCenter: parent.verticalCenter
310 text: "Click to change nextColor property."
311 wrapMode: QQC.Label.WordWrap
312 }
313
314 TapHandler {
315 onTapped: {
316 colorDialog.open()
317 }
318 }
319
320 ColorDialog {
321 id: colorDialog
322 currentColor: objProperties.initialColor
323 onColorChanged: {
324 objProperties.nextColor = color
325
326 }
327 }
328 }
329
330 Row {
331 spacing: 2
332
333 Rectangle {
334 width: 200
335 height: 80
336 color: "red"
337 radius: radiusSlider.value
338
339 QQC.Label {
340 width: parent.width
341 anchors.centerIn: parent
342 text: "Use slider to change radius"
343 wrapMode: QQC.Label.WordWrap
344 horizontalAlignment: Qt.AlignHCenter
345 }
346 }
347
348 QQC.Slider {
349 id: radiusSlider
350 width: 100
351 anchors.verticalCenter: parent.verticalCenter
352 from: 0
353 to: 80
354 }
355 }
356 }
357 }
358}