Developing for Sailfish OS: Creating own QML component in C++
Hello! This article is a continuation of the series of articles dedicated to developing for the mobile platform Sailfish OS. In this article we will talk about creating your own components for the QML in C++, specifically on the creation of properties and methods available in QML, signals and linking. Will show you how to connect a new component to the application.
To begin with you should determine the cases in which the use of components in C++ makes sense. Built-in types Qt Quick course offering some tools for working with sensors, databases and notifications, which we already told earlier here and here with various system features, such as network or Bluetooth, D-Bus. However, these two tools are quite limited and not suitable for creating more complex applications. In this case, C++ allows you to implement functionality beyond what's provided by Qt Quick.
Another argument in favor of C++ is the ability to use a variety of low-level libraries. In addition, complex logic is simply correct to allocate C++ classes. This is what we followed when creating component for displaying data on a time axis in a graph.
The appearance component is a coordinate plane on which are shown various graphs. Moving along the chart to the right and to the left is performed by using the buttons below the component. The data on the plane can be displayed for different time periods: week, month, quarter, or year. However, one of the last three periods of data is summarized. For example, for the month, the graph displays the average values for each day in the range, and for the quarterly and annual range of average values for every 3 and 12 days, respectively. Select the desired period using the buttons, which are located on the coordinate plane

It should be noted that the process of creating components is not different from the one in Qt, but still there are some specific to Sailfish OS features. They will be discussed below.
First we need to create a C++ class derived from QObject or his descendants and contains the macro Q_OBJECT:
the
Our class inherited from QQuickPaintedItem to allow method overriding QQuickPaintedItem::paint(), which is the process of rendering graphics using the interface QPainter. To implement visual components without the use of a drawing you can use the class QQuickItem.
We will show how to create properties that will be visible in QML, and work with them to example properties periodIndex, which is responsible for the index of the current selected period. To declare a property, you must use the macro Q_PROPERTY:
the
As you can see from the example, the properties you must specify its name, type, and the function READ to get the value of the property. You can also specify WRITE function is designed to assign the property to a new value. Full list of available parameters can be viewed here. In addition, inside the class it is best to declare a variable to store the value of the property (which we did in the example).
Also, to use binding inside QML, using the NOTIFY property periodIndex is determined by the signal changing its value. The call signal must be placed inside a method PlotView::setPeriodIndex():
the
For all signals declared in our component, you can create the appropriate handlers in the component Declaration in QML. So, the signal handler on the change in the index of the current period will look like the following:
the
To create a method that will be called within the QML, in its Declaration, you must add the macro Q_INVOKABLE . Declare a method that updates the data for graphs and redraws the component:
the
Now we can add this method call to the handler onPeriodIndexChanged()
the
Thus, if you change the property periodIndex coordinate plane and graphs will be updated automatically.
It should be noted that instead of using Q_INVOKABLE method can be declared as a slot, that will also make it visible inside QML.
The very rendering of a component occurs, as mentioned above, use the standard class provided by the Qt library. An example of rendering the horizontal lines of the coordinate plane as follows:
the
So to make our component is available in QML, you must register it inside the app. It is worth noting several characteristics specific to Sailfish applications, namely their publication in the Harbour shop:
Full list of naming requirements for publishing apps in the store you can see here.
Registration is performed using the method qmlRegisterType() as follows:
the
Thus, the use of this component in QML will look like this:
the
It is important to note that in our components you can use classes and properties from the library Sailfish Silica, thereby creating components satisfying UI and Sailfish OS. A good example for this is class Theme provides access to the standard style properties, Sailfish OS, such as colors, fonts, and indentation:
the
The result was shown the basic steps to create your own components. Similar steps can be used to create non-visual components for your application. More information on this topic can be found here and here. The source code of a small app to demonstrate the operation of our component available at Bitbucket.
Technical questions can be discussed on channel Russian-speaking community of Sailfish OS in Telegram or Facebook page.
Author: Daria Raichinov
Article based on information from habrahabr.ru
Motivation
To begin with you should determine the cases in which the use of components in C++ makes sense. Built-in types Qt Quick course offering some tools for working with sensors, databases and notifications, which we already told earlier here and here with various system features, such as network or Bluetooth, D-Bus. However, these two tools are quite limited and not suitable for creating more complex applications. In this case, C++ allows you to implement functionality beyond what's provided by Qt Quick.
Another argument in favor of C++ is the ability to use a variety of low-level libraries. In addition, complex logic is simply correct to allocate C++ classes. This is what we followed when creating component for displaying data on a time axis in a graph.
Description component
The appearance component is a coordinate plane on which are shown various graphs. Moving along the chart to the right and to the left is performed by using the buttons below the component. The data on the plane can be displayed for different time periods: week, month, quarter, or year. However, one of the last three periods of data is summarized. For example, for the month, the graph displays the average values for each day in the range, and for the quarterly and annual range of average values for every 3 and 12 days, respectively. Select the desired period using the buttons, which are located on the coordinate plane

implementing the component
It should be noted that the process of creating components is not different from the one in Qt, but still there are some specific to Sailfish OS features. They will be discussed below.
First we need to create a C++ class derived from QObject or his descendants and contains the macro Q_OBJECT:
the
#include <QQuickPaintedItem>
#include <QObject>
class PlotView : public QQuickPaintedItem {
Q_OBJECT
public:
explicit PlotView(QQuickItem* parent = NULL);
void paint(QPainter* painter);
};
Our class inherited from QQuickPaintedItem to allow method overriding QQuickPaintedItem::paint(), which is the process of rendering graphics using the interface QPainter. To implement visual components without the use of a drawing you can use the class QQuickItem.
We will show how to create properties that will be visible in QML, and work with them to example properties periodIndex, which is responsible for the index of the current selected period. To declare a property, you must use the macro Q_PROPERTY:
the
class PlotView : public QQuickPaintedItem {
//...
Q_PROPERTY(int periodIndex READ periodIndex WRITE setPeriodIndex NOTIFY periodIndexChanged)
private:
int periodIndexValue;
//...
public:
void setPeriodIndex(int periodIndex);
int periodIndex() const;
//...
signals:
void periodIndexChanged();
};
As you can see from the example, the properties you must specify its name, type, and the function READ to get the value of the property. You can also specify WRITE function is designed to assign the property to a new value. Full list of available parameters can be viewed here. In addition, inside the class it is best to declare a variable to store the value of the property (which we did in the example).
Also, to use binding inside QML, using the NOTIFY property periodIndex is determined by the signal changing its value. The call signal must be placed inside a method PlotView::setPeriodIndex():
the
void PlotView::setPeriodIndex(int periodIndex) {
periodIndexValue = periodIndex;
//...
periodIndexChanged emit();
//...
}
For all signals declared in our component, you can create the appropriate handlers in the component Declaration in QML. So, the signal handler on the change in the index of the current period will look like the following:
the
PlotView {
onPeriodIndexChanged: {}
//...
}
To create a method that will be called within the QML, in its Declaration, you must add the macro Q_INVOKABLE . Declare a method that updates the data for graphs and redraws the component:
the
class PlotView : public QQuickPaintedItem {
//...
public:
Q_INVOKABLE void drawPlot();
//...
};
Now we can add this method call to the handler onPeriodIndexChanged()
the
PlotView {
onPeriodIndexChanged: drawPlot()
}
Thus, if you change the property periodIndex coordinate plane and graphs will be updated automatically.
It should be noted that instead of using Q_INVOKABLE method can be declared as a slot, that will also make it visible inside QML.
The very rendering of a component occurs, as mentioned above, use the standard class provided by the Qt library. An example of rendering the horizontal lines of the coordinate plane as follows:
the
void PlotView::drawVerticalScaleLines(QPainter* painter) {
painter- > setPen(QPen(QBrush(Qt::white), 1));
for (float i = minValue; i < maxValue; i += step) {
int y = calculatePlotYCoordinate(i);
painter- > drawLine(0, y, width(), y);
}
}
So to make our component is available in QML, you must register it inside the app. It is worth noting several characteristics specific to Sailfish applications, namely their publication in the Harbour shop:
-
the
- the Title of your application must begin with harbour and written using "-". For example, harbour-plot-app the
- requires that URI, where you register components, began with the name of the application that "-" is replaced by ".". In our case it will look like harbour.plot.app.plotview
Full list of naming requirements for publishing apps in the store you can see here.
Registration is performed using the method qmlRegisterType() as follows:
the
#include <QtQuick/QQuickView>
#include <QGuiApplication>
#include "plotview.h"
//...
int main(int argc, char *argv[]) {
QGuiApplication* app = SailfishApp::application(argc, argv);
//...
qmlRegisterType<PlotView > ("harbour.plotapp.plotview", 1, 0, "PlotView");
//...
return app- > exec();
}
Thus, the use of this component in QML will look like this:
the
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.plotapp.plotview 1.0
//...
PlotView {
id: plotView
periodIndex: 0
onPeriodIndexChanged: drawPlot();
//...
}
//...
It is important to note that in our components you can use classes and properties from the library Sailfish Silica, thereby creating components satisfying UI and Sailfish OS. A good example for this is class Theme provides access to the standard style properties, Sailfish OS, such as colors, fonts, and indentation:
the
PlotView {
//...
width: parent.width - Theme.horizontalPageMargin * 2
anchors.horizontalCenter: parent.horizontalCenter
//...
}
Opinion
The result was shown the basic steps to create your own components. Similar steps can be used to create non-visual components for your application. More information on this topic can be found here and here. The source code of a small app to demonstrate the operation of our component available at Bitbucket.
Technical questions can be discussed on channel Russian-speaking community of Sailfish OS in Telegram or Facebook page.
Author: Daria Raichinov