Writing QML Extensions with C++▲
The Qt QML module provides a set of APIs for extending QML through C++ extensions. You can write extensions to add your own QML types, extend existing Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
This tutorial shows how to write a QML extension using C++ that includes core QML features, including properties, signals and bindings. It also shows how extensions can be deployed through plugins.
Many of the topics covered in this tutorial are documented in further detail in Integrating QML and C++ and its documentation sub-topics. In particular, you may be interested in the sub-topics Exposing Attributes of C++ Classes to QML and Defining QML Types from C++.
Running the Tutorial Examples▲
The code in this tutorial is available as an example project with subprojects associated with each tutorial chapter. In Qt Creator, open the Welcome mode and select the tutorial from Examples. In Edit mode, expand the extending-qml project, right-click on the subproject (chapter) you want to run and select Run.
Chapter 1: Creating a New Type▲
extending-qml/chapter1-basics
A common task when extending QML is to provide a new QML type that supports some custom functionality beyond what is provided by the built-in Qt Quick types. For example, this could be done to implement particular data models, or provide types with custom painting and drawing capabilities, or access system features like network programming that are not accessible through built-in QML features.
In this tutorial, we will show how to use the C++ classes in the Qt Quick module to extend QML. The end result will be a simple Pie Chart display implemented by several custom QML types connected together through QML features like bindings and signals, and made available to the QML runtime through a plugin.
To begin with, let's create a new QML type called "PieChart" that has two properties: a name and a color. We will make it available in an importable type namespace called "Charts", with a version of 1.0.
We want this PieChart type to be usable from QML like this:
import
Charts 1.0
PieChart {
width
:
100
; height: 100
name
:
"A simple pie chart"
color
:
"red"
}
To do this, we need a C++ class that encapsulates this PieChart type and its two properties. Since QML makes extensive use of Qt's meta object system, this new class must:
-
Inherit from QObject
-
Declare its properties using the Q_PROPERTY macro
Here is our PieChart class, defined in piechart.h:
#include <QtQuick/QQuickPaintedItem>
#include <QColor>
class
PieChart : public
QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QColor color READ color WRITE setColor)
public
:
PieChart(QQuickItem *
parent =
0
);
QString name() const
;
void
setName(const
QString &
amp;name);
QColor color() const
;
void
setColor(const
QColor &
amp;color);
void
paint(QPainter *
painter);
private
:
QString m_name;
QColor m_color;
}
;
The class inherits from QQuickPaintedItem because we want to override QQuickPaintedItem::paint() in perform drawing operations with the QPainter API. If the class just represented some data type and was not an item that actually needed to be displayed, it could simply inherit from QObject. Or, if we want to extend the functionality of an existing QObject-based class, it could inherit from that class instead. Alternatively, if we want to create a visual item that doesn't need to perform drawing operations with the QPainter API, we can just subclass QQuickItem.
The PieChart class defines the two properties, name and color, with the Q_PROPERTY macro, and overrides QQuickPaintedItem::paint(). The class implementation in piechart.cpp simply sets and returns the m_name and m_color values as appropriate, and implements paint() to draw a simple pie chart. It also turns off the QGraphicsItem::ItemHasNoContents flag to enable painting:
PieChart::
PieChart(QQuickItem *
parent)
:
QQuickPaintedItem(parent)
{
}
...
void
PieChart::
paint(QPainter *
painter)
{
QPen pen(m_color, 2
);
painter-&
gt;setPen(pen);
painter-&
gt;setRenderHints(QPainter::
Antialiasing, true
);
painter-&
gt;drawPie(boundingRect().adjusted(1
, 1
, -
1
, -
1
), 90
*
16
, 290
*
16
);
}
Now that we have defined the PieChart type, we will use it from QML. The app.qml file creates a PieChart item and display the pie chart's details using a standard QML Text item:
import
Charts 1.0
import
QtQuick 2.0
Item
{
width
:
300
; height
:
200
PieChart {
id
:
aPieChart
anchors.centerIn
:
parent
width
:
100
; height
:
100
name
:
"A simple pie chart"
color
:
"red"
}
Text
{
anchors {
bottom
:
parent.bottom; horizontalCenter
:
parent.horizontalCenter; bottomMargin
:
20
}
text
:
aPieChart.name
}
}
Notice that although the color is specified as a string in QML, it is automatically converted to a QColor object for the PieChart color property. Automatic conversions are provided for various other basic types; for example, a string like "640x480" can be automatically converted to a QSize value.
We'll also create a C++ application that uses a QQuickView to run and display app.qml. The application must register the PieChart type using the qmlRegisterType() function, to allow it to be used from QML. If you don't register the type, app.qml won't be able to create a PieChart.
Here is the application main.cpp:
#include
"piechart.h"
#include <QtQuick/QQuickView>
#include <QGuiApplication>
int
main(int
argc, char
*
argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType&
lt;PieChart&
gt;("Charts"
, 1
, 0
, "PieChart"
);
QQuickView view;
view.setResizeMode(QQuickView::
SizeRootObjectToView);
view.setSource(QUrl("qrc:///app.qml"
));
view.show();
return
app.exec();
}
This call to qmlRegisterType() registers the PieChart type as a type called "PieChart", in a type namespace called "Charts", with a version of 1.0.
Lastly, we write a .pro project file that includes the files and the declarative library:
QT +=
qml quick
HEADERS +=
piechart.h
SOURCES +=
piechart.cpp \
main.cpp
RESOURCES +=
chapter1-
basics.qrc
DESTPATH =
$$[QT_INSTALL_EXAMPLES]/
qml/
tutorials/
extending-
qml/
chapter1-
basics
target.path =
$$DESTPATH
qml.files =
*
.qml
qml.path =
$$DESTPATH
INSTALLS +=
target qml
Now we can build and run the application:

You may see a warning Expression ... depends on non-NOTIFYable properties: PieChart::name. This happens because we add a binding to the writable name property, but haven't yet defined a notify signal for it. The QML engine therefore cannot update the binding if the name value changes. This is addressed in the following chapters.
The source code from the following files are referred to in this chapter:
Chapter 2: Connecting to C++ Methods and Signals▲
extending-qml/chapter2-methods
Suppose we want PieChart to have a "clearChart()" method that erases the chart and then emits a "chartCleared" signal. Our app.qml would be able to call clearChart() and receive chartCleared() signals like this:
import
Charts 1.0
import
QtQuick 2.0
Item
{
width
:
300
; height
:
200
PieChart {
id
:
aPieChart
anchors.centerIn
:
parent
width
:
100
; height
:
100
color
:
"red"
onChartCleared
:
console.log("The chart has been cleared"
)
}
MouseArea
{
anchors.fill
:
parent
onClicked
:
aPieChart.clearChart()
}
Text
{
anchors {
bottom
:
parent.bottom; horizontalCenter
:
parent.horizontalCenter; bottomMargin
:
20
}
text
:
"Click anywhere to clear the chart"
}
}

To do this, we add a clearChart() method and a chartCleared() signal to our C++ class:
class
PieChart : public
QQuickPaintedItem
{
...
public
:
...
Q_INVOKABLE void
clearChart();
signals
:
void
chartCleared();
...
}
;
The use of Q_INVOKABLE makes the clearChart() method available to the Qt Meta-Object system, and in turn, to QML. Note that it could have been declared as a Qt slot instead of using Q_INVOKABLE, as slots are also callable from QML. Both of these approaches are valid.
The clearChart() method simply changes the color to Qt::transparent, repaints the chart, then emits the chartCleared() signal:
void
PieChart::
clearChart()
{
setColor(QColor(Qt::
transparent));
update();
emit chartCleared();
}
Now when we run the application and click the window, the pie chart disappears, and the application outputs:
qml
:
The chart has been cleared
The source code from the following files are referred to in this chapter:
Chapter 3: Adding Property Bindings▲
extending-qml/chapter3-bindings
Property binding is a powerful feature of QML that allows values of different types to be synchronized automatically. It uses signals to notify and update other types' values when property values are changed.
Let's enable property bindings for the color property. That means if we have code like this:
import
Charts 1.0
import
QtQuick 2.0
Item
{
width
:
300
; height
:
200
Row
{
anchors.centerIn
:
parent
spacing
:
20
PieChart {
id
:
chartA
width
:
100
; height
:
100
color
:
"red"
}
PieChart {
id
:
chartB
width
:
100
; height
:
100
color
:
chartA.color
}
}
MouseArea
{
anchors.fill
:
parent
onClicked
: {
chartA.
color =
"blue"
}
}
Text
{
anchors {
bottom
:
parent.bottom; horizontalCenter
:
parent.horizontalCenter; bottomMargin
:
20
}
text
:
"Click anywhere to change the chart color"
}
}

The "color: chartA.color" statement binds the color value of chartB to the color of chartA. Whenever chartA's color value changes, chartB's color value updates to the same value. When the window is clicked, the onClicked handler in the MouseArea changes the color of chartA, thereby changing both charts to the color blue.
It's easy to enable property binding for the color property. We add a NOTIFY feature to its Q_PROPERTY() declaration to indicate that a "colorChanged" signal is emitted whenever the value changes.
class
PieChart : public
QQuickPaintedItem
{
...
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public
:
...
signals
:
void
colorChanged();
...
}
;
Then, we emit this signal in setPieSlice():
void
PieChart::
setColor(const
QColor &
amp;color)
{
if
(color !=
m_color) {
m_color =
color;
update(); // repaint with the new color
emit colorChanged();
}
}
It's important for setColor() to check that the color value has actually changed before emitting colorChanged(). This ensures the signal is not emitted unnecessarily and also prevents loops when other types respond to the value change.
The use of bindings is essential to QML. You should always add NOTIFY signals for properties if they are able to be implemented, so that your properties can be used in bindings. Properties that cannot be bound cannot be automatically updated and cannot be used as flexibly in QML. Also, since bindings are invoked so often and relied upon in QML usage, users of your custom QML types may see unexpected behavior if bindings are not implemented.
The source code from the following files are referred to in this chapter:
Chapter 4: Using Custom Property Types▲
extending-qml/chapter4-customPropertyTypes
The PieChart type currently has a string-type property and a color-type property. It could have many other types of properties. For example, it could have an int-type property to store an identifier for each chart:
// C++
class
PieChart : public
QQuickPaintedItem
{
Q_PROPERTY(int
chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
...
public
:
void
setChartId(int
chartId);
int
chartId() const
;
...
signals
:
void
chartIdChanged();
}
;
// QML
PieChart {
...
chartId
:
100
}
Aside from int, we could use various other property types. Many of the Qt data types such as QColor, QSize and QRect are automatically supported from QML. (See Data Type Conversion Between QML and C++ documentation for a full list.)
If we want to create a property whose type is not supported by QML by default, we need to register the type with the QML engine.
For example, let's replace the use of the property with a type called "PieSlice" that has a color property. Instead of assigning a color, we assign an PieSlice value which itself contains a color:
import
Charts 1.0
import
QtQuick 2.0
Item
{
width
:
300
; height
:
200
PieChart {
id
:
chart
anchors.centerIn
:
parent
width
:
100
; height
:
100
pieSlice
:
PieSlice {
anchors.fill
:
parent
color
:
"red"
}
}
Component.onCompleted
:
console.log("The pie is colored "
+
chart.pieSlice.color)
}
Like PieChart, this new PieSlice type inherits from QQuickPaintedItem and declares its properties with Q_PROPERTY():
class
PieSlice : public
QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
public
:
PieSlice(QQuickItem *
parent =
0
);
QColor color() const
;
void
setColor(const
QColor &
amp;color);
void
paint(QPainter *
painter);
private
:
QColor m_color;
}
;
To use it in PieChart, we modify the color property declaration and associated method signatures:
class
PieChart : public
QQuickItem
{
Q_OBJECT
Q_PROPERTY(PieSlice*
pieSlice READ pieSlice WRITE setPieSlice)
...
public
:
...
PieSlice *
pieSlice() const
;
void
setPieSlice(PieSlice *
pieSlice);
...
}
;
There is one thing to be aware of when implementing setPieSlice(). The PieSlice is a visual item, so it must be set as a child of the PieChart using QQuickItem::setParentItem() so that the PieChart knows to paint this child item when its contents are drawn:
void
PieChart::
setPieSlice(PieSlice *
pieSlice)
{
m_pieSlice =
pieSlice;
pieSlice-&
gt;setParentItem(this
);
}
Like the PieChart type, the PieSlice type has to be registered using qmlRegisterType() to be used from QML. As with PieChart, we'll add the type to the "Charts" type namespace, version 1.0:
int
main(int
argc, char
*
argv[])
{
...
qmlRegisterType&
lt;PieSlice&
gt;("Charts"
, 1
, 0
, "PieSlice"
);
...
}
The source code from the following files are referred to in this chapter:
Chapter 5: Using List Property Types▲
extending-qml/chapter5-listproperties
Right now, a PieChart can only have one PieSlice. Ideally a chart would have multiple slices, with different colors and sizes. To do this, we could have a slices property that accepts a list of PieSlice items:
import
Charts 1.0
import
QtQuick 2.0
Item
{
width
:
300
; height
:
200
PieChart {
anchors.centerIn
:
parent
width
:
100
; height
:
100
slices
:
[
PieSlice {
anchors.fill
:
parent
color
:
"red"
fromAngle
:
0
; angleSpan
:
110
}
,
PieSlice {
anchors.fill
:
parent
color
:
"black"
fromAngle
:
110
; angleSpan
:
50
}
,
PieSlice {
anchors.fill
:
parent
color
:
"blue"
fromAngle
:
160
; angleSpan
:
100
}
]
}
}

To do this, we replace the pieSlice property in PieChart with a slices property, declared as a QQmlListProperty type. The QQmlListProperty class enables the creation of list properties in QML extensions. We replace the pieSlice() function with a slices() function that returns a list of slices, and add an internal append_slice() function (discussed below). We also use a QList to store the internal list of slices as m_slices:
class
PieChart : public
QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty&
lt;PieSlice&
gt; slices READ slices)
...
public
:
...
QQmlListProperty&
lt;PieSlice&
gt; slices();
private
:
static
void
append_slice(QQmlListProperty&
lt;PieSlice&
gt; *
list, PieSlice *
slice);
QString m_name;
QList&
lt;PieSlice