source: trunk/doc/src/declarative/extending-tutorial.qdoc@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 19.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:FDL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in a
14** written agreement between you and Nokia.
15**
16** GNU Free Documentation License
17** Alternatively, this file may be used under the terms of the GNU Free
18** Documentation License version 1.3 as published by the Free Software
19** Foundation and appearing in the file included in the packaging of this
20** file.
21**
22** If you have questions regarding the use of this file, please contact
23** Nokia at [email protected].
24** $QT_END_LICENSE$
25**
26****************************************************************************/
27
28/*!
29\page qml-extending-tutorial-index.html
30\title Tutorial: Writing QML extensions with C++
31
32The Qt Declarative module provides a set of APIs for extending QML through
33C++ extensions. You can write extensions to add your own QML types, extend existing
34Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
35
36This tutorial shows how to write a QML extension using C++ that includes
37core QML features, including properties, signals and bindings. It also shows how
38extensions can be deployed through plugins.
39
40You can find the source code for this tutorial in \c Qt's
41examples/declarative/tutorials/extending directory.
42
43Tutorial chapters:
44
45\list 1
46\o \l{declarative/tutorials/extending/chapter1-basics}{Creating a New Type}
47\o \l{declarative/tutorials/extending/chapter2-methods}{Connecting to C++ Methods and Signals}
48\o \l{declarative/tutorials/extending/chapter3-bindings}{Adding Property Bindings}
49\o \l{declarative/tutorials/extending/chapter4-customPropertyTypes}{Using Custom Property Types}
50\o \l{declarative/tutorials/extending/chapter5-listproperties}{Using List Property Types}
51\o \l{declarative/tutorials/extending/chapter6-plugins}{Writing an Extension Plugin}
52\o \l{qml-extending-tutorial7.html}{In Summary}
53\endlist
54
55*/
56
57/*!
58\title Chapter 1: Creating a New Type
59
60\example declarative/tutorials/extending/chapter1-basics
61
62A common task when extending QML is to provide a new QML type that supports some
63 custom functionality beyond what is provided by the built-in \l {QML Elements}.
64For example, this could be done to implement particular data models, or provide
65elements with custom painting and drawing capabilities, or access system features
66like network programming that are not accessible through built-in QML features.
67
68In this tutorial, we will show how to use the C++ classes in the Qt Declarative
69module to extend QML. The end result will be a simple Pie Chart display implemented by
70several custom QML types connected together through QML features like bindings and
71signals, and made available to the QML runtime through a plugin.
72
73To begin with, let's create a new QML type called "PieChart" that has two properties: a name
74and a color. We will make it available in a \l {Modules}{module} called "Charts", with
75a module version of 1.0.
76
77We want this \c PieChart type to be usable from QML like this:
78
79\code
80 import Charts 1.0
81
82 PieChart {
83 width: 100; height: 100
84 name: "A simple pie chart"
85 color: "red"
86 }
87\endcode
88
89To do this, we need a C++ class that encapsulates this \c PieChart type and its two
90properties. Since QML makes extensive use of Qt's \l{Meta-Object System}{meta object system},
91this new class must:
92
93\list
94\o Inherit from QObject
95\o Declare its properties using the Q_PROPERTY macro
96\endlist
97
98Here is our \c PieChart class, defined in \c piechart.h:
99
100\snippet declarative/tutorials/extending/chapter1-basics/piechart.h 0
101
102The class inherits from QDeclarativeItem because we want to override
103QDeclarativeItem::paint() in order to draw. If the class just represented some
104data type and was not an item that actually needed to be displayed, it could simply inherit
105from QObject. Or, if we want to extend the functionality of an existing QObject-based
106class, it could inherit from that class instead.
107
108The \c PieChart class defines the two properties, \c name and \c color, with the Q_PROPERTY macro,
109and overrides QDeclarativeItem::paint(). The class implementation in \c piechart.cpp
110simply sets and returns the \c m_name and \c m_color values as appropriate, and
111implements \c paint() to draw a simple pie chart. It also turns off the
112QGraphicsItem::ItemHasNoContents flag to enable painting:
113
114\snippet declarative/tutorials/extending/chapter1-basics/piechart.cpp 0
115\dots 0
116\snippet declarative/tutorials/extending/chapter1-basics/piechart.cpp 1
117
118Now that we have defined the \c PieChart type, we will use it from QML. The \c app.qml
119file creates a \c PieChart item and display the pie chart's details
120using a standard QML \l Text item:
121
122\snippet declarative/tutorials/extending/chapter1-basics/app.qml 0
123
124Notice that although the color is specified as a string in QML, it is automatically
125converted to a QColor object for the PieChart \c color property. Automatic conversions are
126provided for various other \l {QML Basic Types}{basic types}; for example, a string
127like "640x480" can be automatically converted to a QSize value.
128
129We'll also create a C++ application that uses a QDeclarativeView to run and
130display \c app.qml. The application must register the \c PieChart type
131using the qmlRegisterType() function, to allow it to be used from QML. If
132you don't register the type, \c app.qml won't be able to create a \c PieChart.
133
134Here is the application \c main.cpp:
135
136\snippet declarative/tutorials/extending/chapter1-basics/main.cpp 0
137
138This call to qmlRegisterType() registers the \c PieChart type as a type called "PieChart", in a module named "Charts",
139with a module version of 1.0.
140
141Lastly, we write a \c .pro project file that includes the files and the \c declarative library:
142
143\quotefile declarative/tutorials/extending/chapter1-basics/chapter1-basics.pro
144
145Now we can build and run the application:
146
147\image extending-tutorial-chapter1.png
148
149Try it yourself with the code in Qt's \c examples/tutorials/extending/chapter1-basics directory.
150
151At the moment, the \c app.qml is run from within a C++ application.
152This may seem odd if you're used to running QML files with the \l {QML Viewer}.
153Later on, we'll show how to create a plugin so that you can run \c app.qml using the
154\l {QML Viewer} instead.
155
156*/
157
158
159/*!
160\title Chapter 2: Connecting to C++ Methods and Signals
161
162\example declarative/tutorials/extending/chapter2-methods
163
164Suppose we want \c PieChart to have a "clearChart()" method that erases the
165chart and then emits a "chartCleared" signal. Our \c app.qml would be able
166to call \c clearChart() and receive \c chartCleared() signals like this:
167
168\snippet declarative/tutorials/extending/chapter2-methods/app.qml 0
169
170\image extending-tutorial-chapter2.png
171
172To do this, we add a \c clearChart() method and a \c chartCleared() signal
173to our C++ class:
174
175\snippet declarative/tutorials/extending/chapter2-methods/piechart.h 0
176\dots
177\snippet declarative/tutorials/extending/chapter2-methods/piechart.h 1
178\dots
179\snippet declarative/tutorials/extending/chapter2-methods/piechart.h 2
180\dots
181\snippet declarative/tutorials/extending/chapter2-methods/piechart.h 3
182
183The use of Q_INVOKABLE makes the \c clearChart() method available to the
184Qt Meta-Object system, and in turn, to QML. Note that it could have
185been declared as as a Qt slot instead of using Q_INVOKABLE, as
186slots are also callable from QML. Both of these approaches are valid.
187
188The \c clearChart() method simply changes the color to Qt::transparent,
189repaints the chart, then emits the \c chartCleared() signal:
190
191\snippet declarative/tutorials/extending/chapter2-methods/piechart.cpp 0
192
193Now when we run the application and click the window, the pie chart
194disappears, and the application outputs:
195
196\code
197 The chart has been cleared
198\endcode
199
200Try out the example yourself with the updated code in Qt's \c examples/tutorials/extending/chapter2-methods directory.
201
202*/
203
204/*!
205\title Chapter 3: Adding Property Bindings
206
207\example declarative/tutorials/extending/chapter3-bindings
208
209Property bindings is a powerful feature of QML that allows values of different
210elements to be synchronized automatically. It uses signals to notify and update
211other elements' values when property values are changed.
212
213Let's enable property bindings for the \c color property. That means
214if we have code like this:
215
216\snippet declarative/tutorials/extending/chapter3-bindings/app.qml 0
217
218\image extending-tutorial-chapter3.png
219
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.
226
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.
230
231\snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 0
232\dots
233\snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 1
234\dots
235\snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 2
236\dots
237\snippet declarative/tutorials/extending/chapter3-bindings/piechart.h 3
238
239Then, we emit this signal in \c setPieSlice():
240
241\snippet declarative/tutorials/extending/chapter3-bindings/piechart.cpp 0
242
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 elements respond to the value change.
246
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.
253
254*/
255