aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc')
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc269
1 files changed, 217 insertions, 52 deletions
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index 6327ea67e6..7d4f564a6f 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -27,13 +27,13 @@
/*!
\page qtquick-bestpractices.html
-\title Qt Quick Best Practices
-\brief Lists the practices that works best for Qt Quick
+\title Best Practices for QML and Qt Quick
+\brief Lists best practices for working with QML and Qt Quick
-Besides all the benefits that Qt Quick offers, it can be challenging in certain
-situations. For example, a Qt Quick application with a large codebase can be
-painful to maintain if not organized well. The following sections elaborate
-on some of the best practices that will help you get better results.
+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
@@ -48,7 +48,7 @@ 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 to your application's needs, only then it is recommended to create a
+satisfy your application's needs, only then it is recommended to create a
custom control.
@@ -80,79 +80,229 @@ 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
-resource system that is built into the application binary, enabling access to
-the application's resources regardless of the target OS.
+\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.
-It is recommended to bundle your application's resources (including the
-\c .qml files) into a resource file (\c.qrc). For example, the following entry
-in the qmake project file ensures that the resources are built into the
-application binary, making them available when needed:
+For example, consider the following project directory structure:
\badcode
- RESOURCES += resources.qrc
+project
+├── images
+│ ├── image1.png
+│ └── image2.png
+├── project.pro
+└── qml
+ └── main.qml
\endcode
-If your application depends on a limited number of resources, you could list
-them directly in the project file.
+The following entry in \c project.pro ensures that the resources are built into
+the application binary, making them available when needed:
\badcode
- RESOURCES += a.qml b.png
+ RESOURCES += \
+ qml/main.qml \
+ images/image1.png \
+ images/image2.png
\endcode
-In such a case, qmake creates the \c qmake_intermediate.qrc build artifact,
-which you could rename and use the \c{RESOURCES += resource-set.qrc} entry
-instead.
+A more convenient approach is to use the
+\l {files(pattern[, recursive=false])}{wildcard syntax} to select several files
+at once:
-You could go a step further by using one \c .qrc file for each resource type.
-For example, list the \c .qml files in \c files.qrc, images in
-\c images.qrc, fonts in \c fonts.qrc, and so on. That way, you need not
-recompile the QML files when you, for example, add an image to the list in
-\c images.qrc.
+\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 Application UI and Business Logic
+\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 UI from the business logic. The following are a few reasons
-why application's UI should be in QML:
+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 QML is a declarative language, which suits best for defining UIs.
- \li It's easier to embed JavaScript in QML to respond to events, for example.
- \li QML is faster to code as it is not strongly typed.
+ \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
-On the other hand, C++ being a strongly typed language, suits best for defining
-business logic. Typically, such code performs tasks such as complex calculations
-or larger data processing, which can be faster with C++ than with QML.
+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.
-In most cases, the C++ part (business logic) provides the data model to the QML
-part (UI), which presents it in a readable form. It is often a challenge to
-decide when to use this approach. It is recommended to use QML
-if the data model is static, simple, and small, as C++ could be overkill.
-Use C++ if the application depends on a dynamic, large, and complex data model.
+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.
-\omit
-examples snippets of simpler and complex data models.
-\endomit
+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. 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() {}
-\section2 Interaction Path
+ public slots:
+ void restoreDefaults() {
+ settings.setValue("loadLastProject", QVariant(false));
+ }
-Although Qt enables you to manipulate QML from C++, it is not a recommended
-approach, as debugging such code can be painful. The QML engine works out
-a lot of the details on the fly, so manipulating the QML items from C++ could
-lead to unexpected results. This approach also makes the C++ code rely on the
-QML code to provide certain properties or objects, making it difficult to
-refactor the QML code without breaking the C++ code. Moreover, such C++ code
-cannot reused with other QML code. To avoid all of these hassles and have a
-maintainable application, it is recommended to always use the C++ to QML path
-and not the other way around.
+ 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
+
+The problem with this approach 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.
+
+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 exposing the C++ types to 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.
\section2 Related Information
\list
@@ -201,4 +351,19 @@ properties are enough.
\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}.
+
*/