57aa3141ffc9d163ab35e8bcb03f1dabf8ff0bba
[profile/ivi/qtdeclarative.git] / doc / src / declarative / extending-tutorial.qdoc
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the documentation of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:FDL$
10 ** GNU Free Documentation License
11 ** Alternatively, this file may be used under the terms of the GNU Free
12 ** Documentation License version 1.3 as published by the Free Software
13 ** Foundation and appearing in the file included in the packaging of
14 ** this file.
15 **
16 ** Other Usage
17 ** Alternatively, this file may be used in accordance with the terms
18 ** and conditions contained in a signed written agreement between you
19 ** and Nokia.
20 **
21 **
22 **
23 **
24 ** $QT_END_LICENSE$
25 **
26 ****************************************************************************/
27
28 /*!
29 \page qml-extending-tutorial-index.html
30 \inqmlmodule QtQuick 2
31 \title Tutorial: Writing QML Extensions with C++
32
33 The Qt Declarative module provides a set of APIs for extending QML through
34 C++ extensions. You can write extensions to add your own QML types, extend existing
35 Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
36
37 This tutorial shows how to write a QML extension using C++ that includes
38 core QML features, including properties, signals and bindings. It also shows how
39 extensions can be deployed through plugins.
40
41 You can find the source code for this tutorial in \c Qt's
42 examples/declarative/tutorials/extending directory.
43
44 Tutorial chapters:
45
46 \list 1
47 \o \l{declarative/tutorials/extending/chapter1-basics}{Creating a New Type}
48 \o \l{declarative/tutorials/extending/chapter2-methods}{Connecting to C++ Methods and Signals}
49 \o \l{declarative/tutorials/extending/chapter3-bindings}{Property Binding}
50 \o \l{declarative/tutorials/extending/chapter4-customPropertyTypes}{Using Custom Property Types}
51 \o \l{declarative/tutorials/extending/chapter5-listproperties}{Using List Property Types}
52 \o \l{declarative/tutorials/extending/chapter6-plugins}{Writing an Extension Plugin}
53 \o \l{qml-extending-tutorial7.html}{In Summary}
54 \endlist
55
56 */
57
58 /*!
59 \title Chapter 1: Creating a New Type
60
61 \example declarative/tutorials/extending/chapter1-basics
62
63 A common task when extending QML is to provide a new QML type that supports some
64  custom functionality beyond what is provided by the built-in \l {QML Elements}.
65 For example, this could be done to implement particular data models, or provide
66 elements with custom painting and drawing capabilities, or access system features
67 like network programming that are not accessible through built-in QML features.
68
69 In this tutorial, we will show how to use the C++ classes in the Qt Declarative
70 module to extend QML. The end result will be a simple Pie Chart display implemented by
71 several custom QML types connected together through QML features like bindings and
72 signals, and made available to the QML runtime through a plugin.
73
74 To begin with, let's create a new QML type called "PieChart" that has two properties: a name
75 and a color.  We will make it available in a \l {Modules}{module} called "Charts", with
76 a module version of 1.0.
77
78 We want this \c PieChart type to be usable from QML like this:
79
80 \code
81     import Charts 1.0
82
83     PieChart {
84         width: 100; height: 100
85         name: "A simple pie chart"
86         color: "red"
87     }
88 \endcode
89
90 To do this, we need a C++ class that encapsulates this \c PieChart type and its two
91 properties. Since QML makes extensive use of Qt's \l{Meta-Object System}{meta object system},
92 this new class must:
93
94 \list
95 \o Inherit from QObject
96 \o Declare its properties using the Q_PROPERTY macro
97 \endlist
98
99 Here is our \c PieChart class, defined in \c piechart.h:
100
101 \snippet declarative/tutorials/extending/chapter1-basics/piechart.h 0
102
103 The class inherits from QDeclarativeItem because we want to override
104 QDeclarativeItem::paint() in order to draw. If the class just represented some
105 data type and was not an item that actually needed to be displayed, it could simply inherit
106 from QObject. Or, if we want to extend the functionality of an existing QObject-based
107 class, it could inherit from that class instead.
108
109 The \c PieChart class defines the two properties, \c name and \c color, with the Q_PROPERTY macro,
110 and overrides QDeclarativeItem::paint(). The class implementation in \c piechart.cpp
111 simply sets and returns the \c m_name and \c m_color values as appropriate, and
112 implements \c paint() to draw a simple pie chart. It also turns off the
113 QGraphicsItem::ItemHasNoContents flag to enable painting:
114
115 \snippet declarative/tutorials/extending/chapter1-basics/piechart.cpp 0
116 \dots 0
117 \snippet declarative/tutorials/extending/chapter1-basics/piechart.cpp 1
118
119 Now that we have defined the \c PieChart type, we will use it from QML. The \c app.qml
120 file creates a \c PieChart item and display the pie chart's details
121 using a standard QML \l Text item:
122
123 \snippet declarative/tutorials/extending/chapter1-basics/app.qml 0
124
125 Notice that although the color is specified as a string in QML, it is automatically
126 converted to a QColor object for the PieChart \c color property. Automatic conversions are
127 provided for various other \l {QML Basic Types}{basic types}; for example, a string
128 like "640x480" can be automatically converted to a QSize value.
129
130 We'll also create a C++ application that uses a QDeclarativeView to run and
131 display \c app.qml. The application must register the \c PieChart type
132 using the qmlRegisterType() function, to allow it to be used from QML. If
133 you don't register the type, \c app.qml won't be able to create a \c PieChart.
134
135 Here is the application \c main.cpp:
136
137 \snippet declarative/tutorials/extending/chapter1-basics/main.cpp 0
138
139 This call to qmlRegisterType() registers the \c PieChart type as a type called "PieChart", in a module named "Charts",
140 with a module version of 1.0.
141
142 Lastly, we write a \c .pro project file that includes the files and the \c declarative library:
143
144 \quotefile declarative/tutorials/extending/chapter1-basics/chapter1-basics.pro
145
146 Now we can build and run the application:
147
148 \image extending-tutorial-chapter1.png
149
150 Try it yourself with the code in Qt's \c examples/tutorials/extending/chapter1-basics directory.
151
152 At the moment, the \c app.qml is run from within a C++ application.
153 This may seem odd if you're used to running QML files with the \l {QML Viewer}.
154 Later on, we'll show how to create a plugin so that you can run \c app.qml using the
155 \l {QML Viewer} instead.
156
157 */
158
159
160 /*!
161 \title Chapter 2: Connecting to C++ Methods and Signals
162
163 \example declarative/tutorials/extending/chapter2-methods
164
165 Suppose we want \c PieChart to have a "clearChart()" method that erases the
166 chart and then emits a "chartCleared" signal. Our \c app.qml would be able
167 to call \c clearChart() and receive \c chartCleared() signals like this:
168
169 \snippet declarative/tutorials/extending/chapter2-methods/app.qml 0
170
171 \image extending-tutorial-chapter2.png
172
173 To do this, we add a \c clearChart() method and a \c chartCleared() signal
174 to our C++ class:
175
176 \snippet declarative/tutorials/extending/chapter2-methods/piechart.h 0
177 \dots
178 \snippet declarative/tutorials/extending/chapter2-methods/piechart.h 1
179 \dots
180 \snippet declarative/tutorials/extending/chapter2-methods/piechart.h 2
181 \dots
182 \snippet declarative/tutorials/extending/chapter2-methods/piechart.h 3
183
184 The use of Q_INVOKABLE makes the \c clearChart() method available to the
185 Qt Meta-Object system, and in turn, to QML. Note that it could have
186 been declared as as a Qt slot instead of using Q_INVOKABLE, as
187 slots are also callable from QML. Both of these approaches are valid.
188
189 The \c clearChart() method simply changes the color to Qt::transparent,
190 repaints the chart, then emits the \c chartCleared() signal:
191
192 \snippet declarative/tutorials/extending/chapter2-methods/piechart.cpp 0
193
194 Now when we run the application and click the window, the pie chart
195 disappears, and the application outputs:
196
197 \code
198     The chart has been cleared
199 \endcode
200
201 Try out the example yourself with the updated code in Qt's \c examples/tutorials/extending/chapter2-methods directory.
202
203 */
204
205 /*!
206 \title Chapter 3: Adding Property Bindings
207
208 \example declarative/tutorials/extending/chapter3-bindings
209
210 Property bindings is a powerful feature of QML that allows values of different
211 elements to be synchronized automatically. It uses signals to notify and update
212 other elements' values when property values are changed.
213
214 Let's enable property bindings for the \c color property. That means
215 if we have code like this:
216
217 \snippet declarative/tutorials/extending/chapter3-bindings/app.qml 0
218
219 \image extending-tutorial-chapter3.png
220
221 The "color: chartA.color" statement binds the \c color value of
222 \c chartB to the \c color of \c chartA.
223 Whenever \c chartA's \c color value changes, \c chartB's \c color value
224 updates to the same value. When the window is clicked, the \c onClicked
225 handler in the MouseArea changes the color of \c chartA, thereby changing
226 both charts to the color blue.
227
228 It's easy to enable property binding for the \c color property.
229 We add a \l{Qt's Property System}{NOTIFY} feature to its Q_PROPERTY() declaration to indicate that a "colorChanged" signal
230 is emitted whenever the value changes.
231
232 \snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 0
233 \dots
234 \snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 1
235 \dots
236 \snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 2
237 \dots
238 \snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 3
239
240 Then, we emit this signal in \c setPieSlice():
241
242 \snippet declarative/tutorials/extending/chapter3-bindings/piechart.cpp 0
243
244 It's important for \c setColor() to check that the color value has actually changed
245 before emitting \c colorChanged(). This ensures the signal is not emitted unnecessarily and
246 also prevents loops when other elements respond to the value change.
247
248 The use of bindings is essential to QML. You should always add NOTIFY
249 signals for properties if they are able to be implemented, so that your
250 properties can be used in bindings. Properties that cannot be bound cannot be
251 automatically updated and cannot be used as flexibly in QML. Also, since
252 bindings are invoked so often and relied upon in QML usage, users of your
253 custom QML types may see unexpected behavior if bindings are not implemented.
254
255 */
256
257 /*!
258 \title Chapter 4: Using Custom Property Types
259
260 \example declarative/tutorials/extending/chapter4-customPropertyTypes
261
262 The \c PieChart type currently has a string-type property and a color-type property.
263 It could have many other types of properties. For example, it could have an
264 int-type property to store an identifier for each chart:
265
266 \code
267     // C++
268     class PieChart : public QDeclarativeItem
269     {
270         Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
271         ...
272
273     public:
274         void setChartId(int chartId);
275         int chartId() const;
276         ...
277
278     signals:
279         void chartIdChanged();
280     };
281
282     // QML
283     PieChart {
284         ...
285         chartId: 100
286     }
287 \endcode
288
289 We can also use various other property types. QML has built-in support for the types
290 listed in the \l{QML Basic Types} documentation, which includes the following:
291
292 \list
293 \o bool, unsigned int, int, float, double, qreal
294 \o QString, QUrl, QColor
295 \o QDate, QTime, QDateTime
296 \o QPoint, QPointF, QSize, QSizeF, QRect, QRectF
297 \o QVariant
298 \endlist
299
300 If we want to create a property whose type is not supported by QML by default,
301 we need to register the type with QML.
302
303 For example, let's replace the use of the \c property with a type called
304 "PieSlice" that has a \c color property. Instead of assigning a color,
305 we assign an \c PieSlice value which itself contains a \c color:
306
307 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/app.qml 0
308
309 Like \c PieChart, this new \c PieSlice type inherits from QDeclarativeItem and declares
310 its properties with Q_PROPERTY():
311
312 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/pieslice.h 0
313
314 To use it in \c PieChart, we modify the \c color property declaration
315 and associated method signatures:
316
317 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/piechart.h 0
318 \dots
319 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/piechart.h 1
320 \dots
321 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/piechart.h 2
322 \dots
323 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/piechart.h 3
324
325 There is one thing to be aware of when implementing \c setPieSlice(). The \c PieSlice
326 is a visual item, so it must be set as a child of the \c PieChart using
327 QDeclarativeItem::setParentItem() so that the \c PieChart knows to paint this child
328 item when its contents are drawn:
329
330 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/piechart.cpp 0
331
332
333 Like the \c PieChart type, the \c PieSlice type has to be registered
334 using qmlRegisterType() to be used from QML. As with \c PieChart, we'll add the
335 type to the "Charts" module, version 1.0:
336
337 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/main.cpp 0
338 \dots
339 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/main.cpp 1
340 \dots
341 \snippet declarative/tutorials/extending/chapter4-customPropertyTypes/main.cpp 2
342
343 Try it out with the code in Qt's \c examples/tutorials/extending/chapter4-customPropertyTypes directory.
344
345 */
346
347
348 /*!
349 \title Chapter 5: Using List Property Types
350
351 \example declarative/tutorials/extending/chapter5-listproperties
352
353 Right now, a \c PieChart can only have one \c PieSlice. Ideally a chart would
354 have multiple slices, with different colors and sizes. To do this, we could
355 have a \c slices property that accepts a list of \c PieSlice items:
356
357 \snippet declarative/tutorials/extending/chapter5-listproperties/app.qml 0
358
359 \image extending-tutorial-chapter5.png
360
361 To do this, we replace the \c pieSlice property in \c PieChart with a \c slices property,
362 declared as a QDeclarativeListProperty type. The QDeclarativeListProperty class enables the
363 creation of list properties in QML extensions. We replace the \c pieSlice()
364 function with a \c slices() function that returns a list of slices, and add
365 an internal \c append_slice() function (discussed below). We also use a QList to
366 store the internal list of slices as \c m_slices:
367
368 \snippet declarative/tutorials/extending/chapter5-listproperties/piechart.h 0
369 \dots
370 \snippet declarative/tutorials/extending/chapter5-listproperties/piechart.h 1
371 \dots
372 \snippet declarative/tutorials/extending/chapter5-listproperties/piechart.h 2
373
374 Although the \c slices property does not have an associated \c WRITE function,
375 it is still modifiable because of the way QDeclarativeListProperty works.
376 In the \c PieChart implementation, we implement \c PieChart::slices() to
377 return a QDeclarativeListProperty value and indicate that the internal
378 \c PieChart::append_slice() function is to be called whenever a request is made from QML
379 to add items to the list:
380
381 \snippet declarative/tutorials/extending/chapter5-listproperties/piechart.cpp 0
382
383 The \c append_slice() function simply sets the parent item as before,
384 and adds the new item to the \c m_slices list. As you can see, the append function for a
385 QDeclarativeListProperty is called with two arguments: the list property, and
386 the item that is to be appended.
387
388 The \c PieSlice class has also been modified to include \c fromAngle and \c angleSpan
389 properties and to draw the slice according to these values. This is a straightforward
390 modification if you have read the previous pages in this tutorial, so the code is not shown here.
391
392 The complete code can be seen in the updated \c examples/tutorials/extending/chapter5-listproperties directory.
393
394 */
395
396
397 /*!
398 \title Chapter 6: Writing an Extension Plugin
399
400 \example declarative/tutorials/extending/chapter6-plugins
401
402 Currently the \c PieChart and \c PieSlice types are used by \c app.qml,
403 which is displayed using a QDeclarativeView in a C++ application. An alternative
404 way to use our QML extension is to create a plugin library to make it available
405 to the QML engine. This allows \c app.qml to be loaded with the \l {QML Viewer}
406 (or some other QML \l{Qt Declarative UI Runtime}{runtime} application) instead of writing a \c main.cpp file and
407 loading our own C++ application.
408
409 To create a plugin library, we need:
410
411 \list
412 \o A plugin class that registers our QML types
413 \o A project file that describes the plugin
414 \o A \l{Writing a qmldir file}{qmldir} file that tells the QML engine to load the plugin
415 \endlist
416
417 First, we create a plugin class named \c ChartsPlugin. It subclasses QDeclarativeExtensionPlugin
418 and registers our QML types in the inherited \l{QDeclarativeExtensionPlugin::}{registerTypes()} method. It also calls
419 Q_EXPORT_PLUGIN2 for Qt's \l{How to Create Qt Plugins}{plugin system}.
420
421 Here is the \c ChartsPlugin definition in \c chartsplugin.h:
422
423 \snippet declarative/tutorials/extending/chapter6-plugins/chartsplugin.h 0
424
425 And its implementation in \c chartsplugin.cpp:
426
427 \snippet declarative/tutorials/extending/chapter6-plugins/chartsplugin.cpp 0
428
429 Then, we write a \c .pro project file that defines the project as a plugin library
430 and specifies with DESTDIR that library files should be built into a "lib" subdirectory:
431
432 \quotefile declarative/tutorials/extending/chapter6-plugins/chapter6-plugins.pro
433
434 Finally, we add a \l{Writing a qmldir file}{qmldir} file that is automatically parsed by the QML engine.
435 In this file, we specify that a plugin named "chapter6-plugin" (the name
436 of the example project) can be found in the "lib" subdirectory:
437
438 \quotefile declarative/tutorials/extending/chapter6-plugins/qmldir
439
440 Now we have a plugin, and instead of having a main.cpp and an executable, we can build
441 the project and then load the QML file in the \l {QML Viewer}:
442
443 \code
444     qmlviewer app.qml
445 \endcode
446
447 (On Mac OS X, you can launch the "QMLViewer" application instead.)
448
449 Notice the "import Charts 1.0" statement has disappeared from \c app.qml. This is
450 because the \c qmldir file is in the same directory as \c app.qml: this is equivalent to
451 having PieChart.qml and PieSlice.qml files inside the project directory, which could both
452 be used by \c app.qml without import statements.
453 */
454
455
456 /*!
457 \page qml-extending-tutorial7.html
458 \inqmlmodule QtQuick 2
459 \title Chapter 7: In Summary
460
461 In this tutorial, we've shown the basic steps for creating a QML extension:
462
463 \list
464 \o Define new QML types by subclassing QObject and registering them with qmlRegisterType()
465 \o Add callable methods using Q_INVOKABLE or Qt slots, and connect to Qt signals with an \c onSignal syntax
466 \o Add property bindings by defining \l{Qt's Property System}{NOTIFY} signals
467 \o Define custom property types if the built-in types are not sufficient
468 \o Define list property types using QDeclarativeListProperty
469 \o Create a plugin library by defining a Qt plugin and writing a \c qmldir file
470 \endlist
471
472
473 The \l {Extending QML Functionalities using C++} reference documentation shows
474 other useful features that can be added to QML extensions. For example, we
475 could use \l{Default Property}{default properties} to allow
476 slices to be added without using the \c slices property:
477
478 \code
479     PieChart {
480         PieSlice { ... }
481         PieSlice { ... }
482         PieSlice { ... }
483     }
484 \endcode
485
486 Or randomly add and remove slices from time to time using \l{Property Value Sources}{property value sources}:
487
488 \code
489     PieChart {
490         PieSliceRandomizer on slices {}
491     }
492 \endcode
493
494
495 See the \l{Extending QML Functionalities using C++} reference documentation
496 for more information.
497
498 */
499