aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
blob: e70791d1c957b7ae1b58e30fb2c0c7be50406da9 (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
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
/****************************************************************************
**
** Copyright (C) 2018 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 qtquick-bestpractices.html
\title Best Practices for QML and Qt Quick
\brief Lists best practices for working with QML and Qt Quick

Despite all of the benefits that QML and Qt Quick offer, they can be
challenging in certain situations. The following sections elaborate on some of
the best practices that will help you get better results when developing
applications.

\section1 Custom UI Controls

A fluid and modern UI is key for any application's success in today's world, and
that's where QML makes so much sense for a designer or developer. Qt offers the
most basic UI controls that are necessary to create a fluid and modern-looking
UI. It is recommended to browse this list of UI controls before creating your
own custom UI control.

Besides these basic UI controls offered by Qt Quick itself, a rich set of UI
controls are also available with Qt Quick Controls 2. They cater to the most
common use cases without any change, and offer a lot more possibilities with their
customization options. In particular, Qt Quick Controls 2 provides styling
options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.


\section2 Related Information
\list
\li \l{Qt Quick Controls 2}
\li \l{Qt Quick}
\endlist

\section1 Keep it Short and Simple or "KiSS"

QML being a declarative language, a lot of the details are worked out by the underlying
engine. So it is important for any QML application, especially one with a
larger codebase, to have its code organized in smaller and simpler \c .qml files.

\omit
need a few snippet or example applications that showcase this.
\endomit

\section2 Related Information
\list
 \li \l{QML Coding Conventions}
\endlist

\section1 Bundle Application Resources

Most applications depend on resources such as images and icons to provide a
rich user experience. It can often be a challenge to make these resources
available to the application regardless of the target OS. Most popular OS-es
employ stricter security policies that restrict access to the file system,
making it harder to load these resources. As an alternative, Qt offers its own
\l {The Qt Resource System}{resource system} that is built into the
application binary, enabling access to the application's resources regardless
of the target OS.

For example, consider the following project directory structure:

\badcode
project
├── images
│   ├── image1.png
│   └── image2.png
├── project.pro
└── qml
    └── main.qml
\endcode

The following entry in \c project.pro ensures that the resources are built into
the application binary, making them available when needed:

\badcode
    RESOURCES += \
        qml/main.qml \
        images/image1.png \
        images/image2.png
\endcode

A more convenient approach is to use the
\l {files(pattern[, recursive=false])}{wildcard syntax} to select several files
at once:

\badcode
    RESOURCES += \
        $$files(qml/*.qml) \
        $$files(images/*.png)
\endcode

This approach is convenient for applications that depend on a limited number
of resources. However, whenever a new file is added to \c RESOURCES using this
approach, it causes \e all of the other files in \c RESOURCES to be recompiled
as well. This can be inefficient, especially for large sets of files.
In this case, a better approach is to separate each type of resource into its
own \l {Resource Collection Files (.qrc)}{.qrc} file. For example, the snippet
above could be changed to the following:

\badcode
    qml.files = $$files(*.qml)
    qml.prefix = /qml
    RESOURCES += qml

    images.files = $$files(*.png)
    images.prefix = /images
    RESOURCES += images
\endcode

Now, whenever a QML file is changed, only the QML files have to be recompiled.

Sometimes it can be necessary to have more control over the path for a
specific file managed by the resource system. For example, if we wanted to give
\c image2.png an alias, we would need to switch to an explicit \c .qrc file.
\l {Creating Resource Files} explains how to do this in detail.

\section2 Related Information
\list
 \li \l{The Qt Resource System}
\endlist

\section1 Separate UI from Logic

One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
to separate the user interface from the business logic. The following are a few
reasons why an application's UI should be written in QML:

\list
 \li Declarative languages are strongly suited for defining UIs.
 \li QML code is simpler to write, as it is less verbose than C++, and is not
     strongly typed. This also results in it being an excellent language to
     prototype in, a quality that is vital when collaborating with designers,
     for example.
 \li JavaScript can easily be used in QML to respond to events.
\endlist

Being a strongly typed language, C++ is best suited for an application's logic.
Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.

Qt offers various approaches to integrate QML and C++ code in an application.
A typical use case is displaying a list of data in a user interface.
If the data set is static, simple, and/or small, a model written in QML can be
sufficient.

The following snippet demonstrates examples of models written in QML:

\qml
    model: ListModel {
        ListElement { name: "Item 1" }
        ListElement { name: "Item 2" }
        ListElement { name: "Item 3" }
    }

    model: [ "Item 1", "Item 2", "Item 3" ]

    model: 10
\endqml

Use \l {QAbstractItemModel Subclass}{C++} for dynamic data sets that are large
or frequently modified.

\section2 Interacting with QML from C++

Although Qt enables you to manipulate QML from C++, it is not recommended to do
so. To explain why, let's take a look at a simplified example.

\section3 Pulling References from QML

Suppose we were writing the UI for a settings page:

\qml
    import QtQuick 2.11
    import QtQuick.Controls 2.4

    Page {
        Button {
            text: qsTr("Restore default settings")
        }
    }
\endqml

We want the button to do something in C++ when it is clicked. We know objects
in QML can emit change signals just like they can in C++, so we give the button
an \l [QML]{QtObject::}{objectName} so that we can find it from C++:

\qml
    Button {
        objectName: "restoreDefaultsButton"
        text: qsTr("Restore default settings")
    }
\endqml

Then, in C++, we find that object and connect to its change signal:

\code
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QSettings>

    class Backend : public QObject
    {
        Q_OBJECT

    public:
        Backend() {}

    public slots:
        void restoreDefaults() {
            settings.setValue("loadLastProject", QVariant(false));
        }

    private:
        QSettings settings;
    };

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);

        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;

        Backend backend;

        QObject *rootObject = engine.rootObjects().first();
        QObject *restoreDefaultsButton = rootObject->findChild<QObject*>("restoreDefaultsButton");
        QObject::connect(restoreDefaultsButton, SIGNAL(clicked()),
            &backend, SLOT(restoreDefaults()));

        return app.exec();
    }

    #include "main.moc"
\endcode

With this approach, references to objects are "pulled" from QML.
The problem with this is that the C++ logic layer depends on the QML
presentation layer. If we were to refactor the QML in such a way that the
\c objectName changes, or some other change breaks the ability for the C++
to find the QML object, our workflow becomes much more complicated and tedious.

\section3 Pushing References to QML

Refactoring QML is a lot easier than refactoring C++, so in order to make
maintenance pain-free, we should strive to keep C++ types unaware of QML as
much as possible. This can be achieved by "pushing" references to C++ types
into QML:

\code
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);

        Backend backend;

        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("backend", &backend);
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;

        return app.exec();
    }
\endcode

The QML then calls the C++ slot directly:

\qml
    import QtQuick 2.11
    import QtQuick.Controls 2.4

    Page {
        Button {
            text: qsTr("Restore default settings")
            onClicked: backend.restoreDefaults()
        }
    }
\endqml

With this approach, the C++ remains unchanged in the event that the QML needs
to be refactored in the future.

In the example above, we set a context property on the root context to expose
the C++ object to QML. This means that the property is available to every
component loaded by the engine. Context properties are useful for objects that
must be available as soon as the QML is loaded and cannot be instantiated in
QML.

\l {Integrating QML and C++} demonstrates an alternative approach where QML is
made aware of a C++ type so that it can instantiate it itself.

\section2 Related Information
\list
\li \l{Integrating QML and C++}
\li \l{Qt Quick Controls 2 - Chat Tutorial}{Chat application tutorial}
\endlist

\section1 Using Qt Quick Layouts

Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
Unlike its alternative, the item positioners, the Qt Quick Layouts can also
resize its children on window resize. Although Qt Quick Layouts are often
the desired choice for most use cases, the following \e dos and \e{don'ts}
must be considered while using them:

\section2 Dos

\list
 \li Use anchors or the item's width and height properties to specify the size
     of the layout against its parent.
 \li Use the \l Layout attached property to set the size and alignment
     attributes of the layout's immediate children.
\endlist

\section2 Don'ts

\list
 \li Do not rely on anchors to specify the preferred size of an item in a layout.
     Instead, use \c Layout.preferredWidth and \c Layout.preferredHeight.
 \li Do not define preferred sizes for items that provide implicitWidth and
     implicitHeight, unless their implicit sizes are not satisfactory.
 \li Do not mix anchors and layouts in ways that cause conflicts. For example,
     do not apply anchor constraints to a layout's immediate children.

    \snippet qml/windowconstraints.qml rowlayout
\endlist

\note Layouts and anchors are both types of objects that take more memory and
instantiation time. Avoid using them (especially in list and table delegates,
and styles for controls) when simple bindings to x, y, width, and height
properties are enough.

\section2 Related Information

\list
 \li \l{Item Positioners}
 \li \l{Qt Quick Layouts Overview}
\endlist

\section1 Performance

For information on performance in QML and Qt Quick,
see \l {Performance Considerations And Suggestions}.

\section1 Tools and Utilities

For information on useful tools and utilies that make working with QML and
Qt Quick easier, see \l {Qt Quick Tools and Utilities}.

\section1 Scene Graph

For information on Qt Quick's scene graph, see \l {Qt Quick Scene Graph}.

\section1 Scalable User Interfaces

As display resolutions improve, a scalable application UI becomes more and
more important. One of the approaches to achieve this is to maintain several
copies of the UI for different screen resolutions, and load the appropriate one
depending on the available resolution. Although this works pretty
well, it adds to the maintenance overhead.

Qt offers a better solution to this problem and recommends the application
developers to follow these tips:

\list
 \li Use anchors or the Qt Quick Layouts module to lay out the visual items.
 \li Do not specify explicit width and height for a visual item.
 \li Provide UI resources such as images and icons for each display resolution
     that your application supports. The Qt Quick Controls 2 gallery example
     demonstrates this well by providing the \c qt-logo.png for \c @2x, \c @3x,
     and \c @4x resolutions, enabling the application to cater to high
     resolution displays. Qt automatically chooses the appropriate
     image that is suitable for the given display, provided the high DPI scaling
     feature is explicitly enabled.
 \li Use SVG images for small icons. While larger SVGs can be slow to render,
     small ones work well. Vector images avoid the need to provide several
     versions of an image, as is necessary with bitmap images.
 \li Use font-based icons, such as Font Awesome. These scale to any display
     resolution, and also allow colorization. The
     Qt Quick Controls 2 Text Editor example demonstrates this well.
\endlist

With this in place, your application's UI should scale depending
on the display resolution on offer.

\image qtquickcontrols2-gallery-welcome.png

\section2 Related Information

\list
 \li \l{Qt Quick Controls2 - Gallery Example}{Gallery example}
 \li \l{Qt Quick Controls 2 - Text Editor}{Text Editor example}
 \li \l{Font Awesome}
 \li \l{Scalability}
 \li \l{High DPI Displays}
\endlist
*/