1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
5\page qtqml-tutorials-extending-qml-example.html
6\title Writing QML Extensions with C++
7\brief Tutorial about extending QML with Qt C++.
9The \l {Qt Qml} module provides a set of APIs for extending QML through
10C++ extensions. You can write extensions to add your own QML types, extend existing
11Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
13This tutorial shows how to write a QML extension using C++ that includes
14core QML features, including properties, signals and bindings. It also shows how
15extensions can be deployed through plugins.
17Many of the topics covered in this tutorial are documented in further detail in
18\l{Overview - QML and C++ Integration} and its documentation sub-topics. In
19particular, you may be interested in the sub-topics
20\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Classes to QML}
21and \l {qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
23\section1 Opening the Tutorial Sources
25The code in this tutorial is available as part of the Qt sources.
26If you installed Qt with the \QOI, you can
27find the sources in the Qt installation directory under
28Examples/Qt-\QtVersion/qml/tutorials/extending-qml/.
30\section1 Creating Project from Scratch
32Alternatively, you can follow the tutorial by creating the sources from scratch:
33For each chapter, create a new project using the \e {Qt Quick Application} template
34in Qt Creator, as instructed in \l {Qt Creator: Creating Qt Quick Projects}.
35Then follow along by adapting and extending the generated skeleton code.
37\section1 Chapter 1: Creating a New Type
38\c extending-qml/chapter1-basics
40A common task when extending QML is to provide a new QML type that supports some
41 custom functionality beyond what is provided by the built-in \l {Qt Quick QML Types}{Qt Quick types}.
42For example, this could be done to implement particular data models, or provide
43types with custom painting and drawing capabilities, or access system features
44like network programming that are not accessible through built-in QML features.
46In this tutorial, we will show how to use the C++ classes in the Qt Quick
47module to extend QML. The end result will be a simple Pie Chart display implemented by
48several custom QML types connected together through QML features like bindings and
49signals, and made available to the QML runtime through a plugin.
51To begin with, let's create a new QML type called "PieChart" that has two properties: a name
52and a color. We will make it available in an importable type namespace called "Charts", with
55We want this \c PieChart type to be usable from QML like this:
61 width: 100; height: 100
62 name: "A simple pie chart"
67To do this, we need a C++ class that encapsulates this \c PieChart type and its two
68properties. Since QML makes extensive use of Qt's \l{Meta-Object System}{meta object system},
72\li Inherit from QObject
73\li Declare its properties using the Q_PROPERTY macro
76\section2 Class Declaration
78Here is our \c PieChart class, defined in \c piechart.h:
80\snippet tutorials/extending-qml/chapter1-basics/piechart.h 0
82The class inherits from QQuickPaintedItem because we want to override
83QQuickPaintedItem::paint() to perform drawing operations with the QPainter API.
84If the class just represented some data type and was not an item that actually needed
85to be displayed, it could simply inherit from QObject. Or, if we want to extend the
86functionality of an existing QObject-based class, it could inherit from that class instead.
87Alternatively, if we want to create a visual item that doesn't need to perform drawing
88operations with the QPainter API, we can just subclass QQuickItem.
90The \c PieChart class defines the two properties, \c name and \c color, with the
91Q_PROPERTY macro, and overrides QQuickPaintedItem::paint(). The \c PieChart
92class is registered using the QML_ELEMENT macro, to allow it to be used from
93QML. If you don't register the class, \c App.qml won't be able to create a
98For the registration to take effect, the \c qmltypes option is added to
99\c CONFIG in the project file and a \c QML_IMPORT_NAME and
100\c QML_IMPORT_MAJOR_VERSION are given:
102\snippet tutorials/extending-qml/chapter1-basics/chapter1-basics.pro 0
106Similarly, for the registration to take effect when using CMake, use the
107\l{qt6_add_qml_module} {qt_add_qml_module} command:
109\snippet tutorials/extending-qml/chapter1-basics/CMakeLists.txt 0
111\section2 Class Implementation
113The class implementation in \c piechart.cpp simply sets and returns the
114\c m_name and \c m_color values as appropriate, and implements \c paint() to
115draw a simple pie chart:
117\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 0
119\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 1
123Now that we have defined the \c PieChart type, we will use it from QML. The \c
124App.qml file creates a \c PieChart item and displays the pie chart's details
125using a standard QML \l Text item:
127\snippet tutorials/extending-qml/chapter1-basics/App.qml 0
129Notice that although the color is specified as a string in QML, it is automatically
130converted to a QColor object for the PieChart \c color property. Automatic conversions are
131provided for various other \l {QML Value Types}{value types}. For example, a string
132like "640x480" can be automatically converted to a QSize value.
134We'll also create a C++ application that uses a QQuickView to run and
137Here is the application \c main.cpp:
139\snippet tutorials/extending-qml/chapter1-basics/main.cpp 0
141\section2 Project Build
143To build the project we include the files, link against the libraries, and
144define a type namespace called "Charts" with version 1.0 for any types exposed
149\quotefile tutorials/extending-qml/chapter1-basics/chapter1-basics.pro
153\quotefile tutorials/extending-qml/chapter1-basics/CMakeLists.txt
155Now we can build and run the application:
157\image extending-tutorial-chapter1.png
159\note You may see a warning \e {Expression ... depends on non-NOTIFYable properties:
160 PieChart::name}. This happens because we add a binding to the writable \c name
161 property, but haven't yet defined a notify signal for it. The QML engine therefore
162 cannot update the binding if the \c name value changes. This is addressed in
163 the following chapters.
165\section1 Chapter 2: Connecting to C++ Methods and Signals
166\c extending-qml/chapter2-methods
168Suppose we want \c PieChart to have a "clearChart()" method that erases the
169chart and then emits a "chartCleared" signal. Our \c App.qml would be able
170to call \c clearChart() and receive \c chartCleared() signals like this:
172\snippet tutorials/extending-qml/chapter2-methods/App.qml 0
174\image extending-tutorial-chapter2.png
176To do this, we add a \c clearChart() method and a \c chartCleared() signal
179\snippet tutorials/extending-qml/chapter2-methods/piechart.h 0
181\snippet tutorials/extending-qml/chapter2-methods/piechart.h 1
183\snippet tutorials/extending-qml/chapter2-methods/piechart.h 2
185\snippet tutorials/extending-qml/chapter2-methods/piechart.h 3
187The use of Q_INVOKABLE makes the \c clearChart() method available to the
188Qt Meta-Object system, and in turn, to QML. Note that it could have
189been declared as a Qt slot instead of using Q_INVOKABLE, as
190slots are also callable from QML. Both of these approaches are valid.
192The \c clearChart() method simply changes the color to Qt::transparent,
193repaints the chart, then emits the \c chartCleared() signal:
195\snippet tutorials/extending-qml/chapter2-methods/piechart.cpp 0
197Now when we run the application and click the window, the pie chart
198disappears, and the application outputs:
201 qml: The chart has been cleared
206\section1 Chapter 3: Adding Property Bindings
207\c extending-qml/chapter3-bindings
209Property binding is a powerful feature of QML that allows values of different
210types to be synchronized automatically. It uses signals to notify and update
211other types' values when property values are changed.
213Let's enable property bindings for the \c color property. That means
214if we have code like this:
216\snippet tutorials/extending-qml/chapter3-bindings/App.qml 0
218\image extending-tutorial-chapter3.png
220The "color: chartA.color" statement binds the \c color value of
221\c chartB to the \c color of \c chartA.
222Whenever \c chartA's \c color value changes, \c chartB's \c color value
223updates to the same value. When the window is clicked, the \c onClicked
224handler in the MouseArea changes the color of \c chartA, thereby changing
225both charts to the color blue.
227It's easy to enable property binding for the \c color property.
228We add a \l{Qt's Property System}{NOTIFY} feature to its Q_PROPERTY() declaration to indicate that a "colorChanged" signal
229is emitted whenever the value changes.
231\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 0
233\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 1
235\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 2
237\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 3
239Then, we emit this signal in \c setColor():
241\snippet tutorials/extending-qml/chapter3-bindings/piechart.cpp 0
243It's important for \c setColor() to check that the color value has actually changed
244before emitting \c colorChanged(). This ensures the signal is not emitted unnecessarily and
245also prevents loops when other types respond to the value change.
247The use of bindings is essential to QML. You should always add NOTIFY
248signals for properties if they are able to be implemented, so that your
249properties can be used in bindings. Properties that cannot be bound cannot be
250automatically updated and cannot be used as flexibly in QML. Also, since
251bindings are invoked so often and relied upon in QML usage, users of your
252custom QML types may see unexpected behavior if bindings are not implemented.
256\section1 Chapter 4: Using Custom Property Types
258\c extending-qml/chapter4-customPropertyTypes
260The \c PieChart type currently has a string-type property and a color-type property.
261It could have many other types of properties. For example, it could have an
262int-type property to store an identifier for each chart:
266 class PieChart : public QQuickPaintedItem
268 Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
272 void setChartId(int chartId);
277 void chartIdChanged();
287Aside from \c int, we could use various other property types. Many of the Qt
288data types such as QColor, QSize and QRect are automatically supported from QML.
289(See \l {Data Type Conversion Between QML and C++} documentation for a full list.)
291If we want to create a property whose type is not supported by QML by default,
292we need to register the type with the QML engine.
294For example, let's replace the use of the \c property with a type called
295"PieSlice" that has a \c color property. Instead of assigning a color,
296we assign an \c PieSlice value which itself contains a \c color:
298\snippet tutorials/extending-qml/chapter4-customPropertyTypes/App.qml 0
300Like \c PieChart, this new \c PieSlice type inherits from QQuickPaintedItem and declares
301its properties with Q_PROPERTY():
303\snippet tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h 0
305To use it in \c PieChart, we modify the \c color property declaration
306and associated method signatures:
308\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 0
310\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 1
312\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 2
314\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 3
316There is one thing to be aware of when implementing \c setPieSlice(). The \c PieSlice
317is a visual item, so it must be set as a child of the \c PieChart using
318QQuickItem::setParentItem() so that the \c PieChart knows to paint this child
319item when its contents are drawn:
321\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp 0
323Like the \c PieChart type, the \c PieSlice type has to be exposted to QML
326\snippet tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h 0
329As with \c PieChart, we add the "Charts" type namespace, version 1.0, to our
334\quotefile tutorials/extending-qml/chapter4-customPropertyTypes/chapter4-customPropertyTypes.pro
339\snippet tutorials/extending-qml/chapter4-customPropertyTypes/CMakeLists.txt 0
340\snippet tutorials/extending-qml/chapter4-customPropertyTypes/CMakeLists.txt 1
345\section1 Chapter 5: Using List Property Types
346\c extending-qml/chapter5-listproperties
348Right now, a \c PieChart can only have one \c PieSlice. Ideally a chart would
349have multiple slices, with different colors and sizes. To do this, we could
350have a \c slices property that accepts a list of \c PieSlice items:
352\snippet tutorials/extending-qml/chapter5-listproperties/App.qml 0
354\image extending-tutorial-chapter5.png
356To do this, we replace the \c pieSlice property in \c PieChart with a \c slices property,
357declared as a QQmlListProperty type. The QQmlListProperty class enables the
358creation of list properties in QML extensions. We replace the \c pieSlice()
359function with a \c slices() function that returns a list of slices, and add
360an internal \c append_slice() function (discussed below). We also use a QList to
361store the internal list of slices as \c m_slices:
363\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 0
365\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 1
367\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 2
369Although the \c slices property does not have an associated \c WRITE function,
370it is still modifiable because of the way QQmlListProperty works.
371In the \c PieChart implementation, we implement \c PieChart::slices() to
372return a QQmlListProperty value and indicate that the internal
373\c PieChart::append_slice() function is to be called whenever a request is made from QML
374to add items to the list:
376\snippet tutorials/extending-qml/chapter5-listproperties/piechart.cpp 0
378The \c append_slice() function simply sets the parent item as before,
379and adds the new item to the \c m_slices list. As you can see, the append function for a
380QQmlListProperty is called with two arguments: the list property, and
381the item that is to be appended.
383The \c PieSlice class has also been modified to include \c fromAngle and \c angleSpan
384properties and to draw the slice according to these values. This is a straightforward
385modification if you have read the previous pages in this tutorial, so the code is not shown here.
389\section1 Chapter 6: Writing an Extension Plugin
391\c extending-qml/chapter6-plugins
393Currently the \c PieChart and \c PieSlice types are used by \c App.qml,
394which is displayed using a QQuickView in a C++ application. An alternative
395way to use our QML extension is to create a plugin library to make it available
396to the QML engine as a new QML import module. This allows the \c PieChart and
397\c PieSlice types to be registered into a type namespace which can be imported
398by any QML application, instead of restricting these types to be only used by
401The steps for creating a plugin are described in \l {Creating C++ Plugins for QML}.
402To start with, we create a plugin class named \c ChartsPlugin. It subclasses
403QQmlEngineExtensionPlugin and uses the Q_PLUGIN_METADATA() macro to register the
404plugin with the Qt meta object system.
406Here is the \c ChartsPlugin definition in \c chartsplugin.h:
408\snippet tutorials/extending-qml/chapter6-plugins/Charts/chartsplugin.h 0
410Then, we configure the build file to define the project as a plugin library.
414\quotefile tutorials/extending-qml/chapter6-plugins/Charts/Charts.pro
418\quotefile tutorials/extending-qml/chapter6-plugins/Charts/CMakeLists.txt
420When building this example on Windows or Linux, the \c Charts directory will be
421located at the same level as the application that uses our new import module.
422This way, the QML engine will find our module as the default search path for QML
423imports includes the directory of the application executable. On \macos, the
424plugin binary is copied to \c Contents/PlugIns in the the application bundle.
425With qmake, this path is set in \c {chapter6-plugins/app.pro}:
427\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro
431To account for this, we also need to add this location as a
432\l {QML Import Path}{QML import path} in \c main.cpp:
434\snippet tutorials/extending-qml/chapter6-plugins/main.cpp 0
437Defining custom import paths is useful also when there are multiple
438applications using the same QML imports.
440The \c .pro file also contains additional magic to ensure that the
441\l {Module Definition qmldir Files}{module definition qmldir file} is always copied
442to the same location as the plugin binary.
444The \c qmldir file declares the module name and the plugin that is made available
447\quotefile tutorials/extending-qml/chapter6-plugins/Charts/qmldir
449Now we have a QML module that can be imported to any application, provided that the
450QML engine knows where to find it. The example contains an executable that loads
451\c App.qml, which uses the \c {import Charts 1.0} statement. Alternatively, you can
452load the QML file using the \l {Prototyping with the QML Runtime Tool}{qml tool},
453setting the import path to the current directory so that it finds the \c qmldir file:
459The module "Charts" will be loaded by the QML engine, and the types provided by that
460module will be available for use in any QML document which imports it.
464\section1 Chapter 7: Summary
466In this tutorial, we've shown the basic steps for creating a QML extension:
469\li Define new QML types by subclassing QObject and registering them with
470 QML_ELEMENT or QML_NAMED_ELEMENT()
471\li Add callable methods using \l Q_INVOKABLE or Qt slots, and connect to Qt signals
472 with an \c onSignal syntax
473\li Add property bindings by defining \l{Qt's Property System}{NOTIFY} signals
474\li Define custom property types if the built-in types are not sufficient
475\li Define list property types using QQmlListProperty
476\li Create a plugin library by defining a Qt plugin and writing a
477 \l {Module Definition qmldir Files}{qmldir} file
480The \l{Overview - QML and C++ Integration}{QML and C++ Integration overview}
481documentation shows other useful features that can be added to QML extensions.
482For example, we could use \l{Default Properties}{default properties} to allow
483slices to be added without using the \c slices property:
493Or randomly add and remove slices from time to time using \l{Property Value Sources}{property value sources}:
497 PieSliceRandomizer on slices {}
501\note To continue learning about QML extensions and features follow the
502\l {Writing advanced QML Extensions with C++} tutorial.