1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
|
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms
** and conditions contained in a signed written agreement between you
** and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\page qml-c++types.html
\title C++ Types as QML Types
\brief exposing Qt C++ types into the QML engine
The \l{The QML Engine}{QML engine} can instantiate any Qt C++ construct
such as \l{The Property System}{properties}, functions, and data models into
the QML context allowing the constructs to be accessible from within QML.
\target register-c++-type
\section1 Register a Type
In an application or a \l{QML Plugins}{plugin}, the \c qmlRegisterType
template will register a class to the QML engine.
\code
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
\endcode
\l qmlRegisterType() registers the C++ type \a T with the QML system, and
makes it available to the QML context under the name \c qmlName in library
\c uri version \c versionMajor.versionMinor. The \c qmlName can be the same
as the C++ type name.
Suppose that a \c Person class defined in a C++ is to be exposed into the
QML context. The class must be a subclass of \l{QObject} and have a default
constructor. The \l{The Property System}{properties} created with the
Q_PROPERTY macro are visible in the QML context as well.
\snippet examples/qml/cppextensions/referenceexamples/adding/person.h 0
The application registers the class to the runtime with the
\l{qmlRegisterType()}.
\snippet examples/qml/cppextensions/referenceexamples/adding/main.cpp 0
The Person type is then imported with the \c "People 1.0" module and its
properties are accessible in a QML file.
\snippet examples/qml/cppextensions/referenceexamples/adding/example.qml 0
The \l {Extending QML - Adding Types Example}{Adding Types} example
demonstrates as usage of the \l qmlRegisterType().
Alternatively, these functions provide a way for other types of C++ types
to be visible in the QML context.
\list
\li \l qmlRegisterModuleApi() is suited for registering either a QJSValue
or QObject module API (shared instance) into a namespace
\li \l qmlRegisterUncreatableType() is suited for attached
properties and enum types.
\li \l qmlRegisterTypeNotAvailable() is for
reserving a namespace and suited for generating useful errors.
\li \l qmlRegisterInterface() - for registering base or abstract classes for
\l{qml-c++-coercion}{coercion and inheritance}. This is useful for general
Qt objects or \l{Qt Objects and Interfaces}{pointers} to objects.
\li \l qmlRegisterExtendedType() - for \l{qml-c++-extension}{extended types}
\endlist
\section2 Qt Objects and Interfaces
QML can bind to complex objects such as pointers to objects or lists. As QML
is typesafe, the \l{The QML Engine}{QML engine} ensures that only
valid types are assigned to these properties.
The QML engine treats pointers to objects or Qt interfaces the same
way as regular properties. Thus, the lists or pointers are created as
properties using the Q_PROPERTY() macro.
\snippet examples/qml/cppextensions/referenceexamples/properties/birthdayparty.h 1
The \c host is an \l{qml-expose-properties}{exposed property} that can bind
to objects or lists of objects. The property type, in this case \c Person,
must be \l{register-c++-type}{registered} into the runtime.
QML also supports assigning Qt interfaces. To assign to a property whose
type is a Qt interface pointer, the interface must also be registered with
QML. As they cannot be instantiated directly, registering a Qt interface is
different from registering a new QML type. The following function is used
instead:
\code
template<typename T>
int qmlRegisterInterface(const char *typeName)
\endcode
This function registers the C++ interface \a T with the QML system as \a
typeName.
Following registration, QML can \l{qml-c++-coercion}{coerce} objects that
implement this interface for assignment to appropriately typed properties.
\section1 Type Revisions and Versions
Type revisions and versions allow new properties or methods to exist in the
new version while remaining compatible with previous versions.
Consider these two QML files:
\code
// main.qml
import QtQuick 1.0
Item {
id: root
MyComponent {}
}
\endcode
\code
// MyComponent.qml
import MyModule 1.0
CppItem {
value: root.x
}
\endcode
where \c CppItem maps to the C++ class \c QCppItem.
If the author of QCppItem adds a \c root property to QCppItem in a new
version of the module, \c root.x now resolves to a different value because
\c root is also the \c id of the top level component. The author could
specify that the new \c root property is available from a specific minor
version. This permits new properties and features to be added to existing
elements without breaking existing programs.
The REVISION tag is used to mark the \c root property as added in revision 1
of the class. Methods such as Q_INVOKABLE's, signals and slots can also be
tagged for a revision using the \c Q_REVISION(x) macro:
\code
class CppElement : public BaseObject
{
Q_OBJECT
Q_PROPERTY(int root READ root WRITE setRoot NOTIFY rootChanged REVISION 1)
signals:
Q_REVISION(1) void rootChanged();
};
\endcode
To register the new class revision to a particular version the following function is used:
\code
template<typename T, int metaObjectRevision>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
\endcode
To register \c CppElement version 1 for \c {MyModule 1.1}:
\code
qmlRegisterType<QCppElement,1>("MyModule", 1, 1, "CppElement")
\endcode
\c root is only available when MyModule 1.1 is imported.
For the same reason, new elements introduced in later versions should use
the minor version argument of qmlRegisterType.
This feature of the language allows for behavioural changes to be made
without breaking existing applications. Consequently QML module authors
should always remember to document what changed between minor versions, and
QML module users should check that their application still runs correctly
before deploying an updated import statement.
You may also register the revision of a base class that your module depends upon
using the qmlRegisterRevision() function:
\code
template<typename T, int metaObjectRevision>
int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
\endcode
For example, if \c BaseObject is changed and now has a revision 1, you can specify that
your module uses the new revision:
\code
qmlRegisterRevision<BaseObject,1>("MyModule", 1, 1);
\endcode
This is useful when deriving from base classes not declared as part of your
module, e.g. when extending classes from the QtQuick library.
The revision feature of QML allows for behavioral changes without breaking
existing applications. Consequently, QML module authors should always
remember to document what changed between minor versions, and QML module
users should check that their application still runs correctly before
deploying an updated import statement.
\target qml-c++-coercion
\section1 Inheritance and Coercion
QML supports C++ inheritance hierarchies and can freely coerce between
known, valid object types. This enables the creation of common base classes
that allow the assignment of specialized classes to object or list
properties.
\snippet examples/qml/cppextensions/referenceexamples/coercion/example.qml 0
The QML snippet shown above assigns a \c Boy object to the \c
BirthdayParty's \c host property, and assigns three other objects to the \c
guests property. Both the \c host and the \c guests properties binds to the
\c Person type, but the assignment is valid as both the \c Boy and \c Girl
objects inherit from \c Person.
To assign to a property, the property's type must have been
\l{register-c++-type}{registered} to the \l{The QML Engine}{declarative
runtime}. If a type that acts purely as a base class that cannot be
instantiated from QML needs to be registered as well. The
\l qmlRegisterType() is useful for this occasion.
\code
template<typename T>
int qmlRegisterType()
\endcode
This function registers the C++ type \a T with the QML system. The
parameterless call to the template function qmlRegisterType() does not
define a mapping between the C++ class and a QML element name, so the type
is not instantiable from QML, but it is available for type coercion.
\snippet examples/qml/cppextensions/referenceexamples/coercion/main.cpp 0
\snippet examples/qml/cppextensions/referenceexamples/coercion/main.cpp register boy girl
The \c Person class is registered withouth the parameters. Both the
\c Boy and \c Girl class derive from the \c Person class.
Type \a T must inherit QObject, but there are no restrictions on whether it
is concrete or the signature of its constructor.
QML will automatically coerce C++ types when assigning to either an object
property, or to a list property. Only if coercion fails does an assignment
error occur.
The \l{Extending QML - Inheritance and Coercion Example}{Inheritance and Coercion Example}
shows the complete code used to create the \c Boy and \c Girl types.
\target qml-c++-extension
\section1 Extension Objects
\snippet examples/qml/cppextensions/referenceexamples/extended/example.qml 0
The \c leftMargin property is a new property to an existing C++ type,
\l QLineEdit, without modifying its source code.
When integrating existing classes and technology into QML, APIs will
often need tweaking to fit better into the declarative environment.
Although the best results are usually obtained by modifying the original
classes directly, if this is either not possible or is complicated by some
other concerns, extension objects allow limited extension possibilities
without direct modifications.
\e{Extension objects} add additional properties to an existing type.
Extension objects can only add properties, not signals or methods. An
extended type definition allows the programmer to supply an additional type,
known as the \e{extension type}, when registering the class. The
properties are transparently merged with the original target class when used
from within QML.
The \l qmlRegisterExtendedType() is for registering extended types. Note
that it has two forms.
\code
template<typename T, typename ExtendedT>
int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
template<typename T, typename ExtendedT>
int qmlRegisterExtendedType()
\endcode
functions should be used instead of the regular \c qmlRegisterType() variations.
The arguments are identical to the corresponding non-extension registration functions,
except for the ExtendedT parameter which is the type
of the extension object.
An extension class is a regular QObject, with a constructor that takes a
QObject pointer. However, the extension class creation is delayed until the
first extended property is accessed. The extension class is created and the
target object is passed in as the parent. When the property on the original
is accessed, the corresponding property on the extension object is used
instead.
The \l{Extending QML - Extension Objects}{Extension Objects} example
demonstrates a usage of extension objects.
\section1 Property Value Sources
\snippet examples/qml/cppextensions/referenceexamples/valuesource/example.qml 0
\snippet examples/qml/cppextensions/referenceexamples/valuesource/example.qml 1
The QML snippet shown above applies a property value source to the \c announcement property.
A property value source generates a value for a property that changes over time.
Property value sources are most commonly used to do animation. Rather than
constructing an animation object and manually setting the animation's "target"
property, a property value source can be assigned directly to a property of any
type and automatically set up this association.
The example shown here is rather contrived: the \c announcement property of the
\c BirthdayParty object is a string that is printed every time it is assigned and
the \c HappyBirthdaySong value source generates the lyrics of the song
"Happy Birthday".
\snippet examples/qml/cppextensions/referenceexamples/valuesource/birthdayparty.h 0
Normally, assigning an object to a string property would not be allowed. In
the case of a property value source, rather than assigning the object instance
itself, the QML engine sets up an association between the value source and
the property.
Property value sources are special types that derive from the
QQmlPropertyValueSource base class. This base class contains a single method,
QQmlPropertyValueSource::setTarget(), that the QML engine invokes when
associating the property value source with a property. The relevant part of
the \c HappyBirthdaySong type declaration looks like this:
\snippet examples/qml/cppextensions/referenceexamples/valuesource/happybirthdaysong.h 0
\snippet examples/qml/cppextensions/referenceexamples/valuesource/happybirthdaysong.h 1
\snippet examples/qml/cppextensions/referenceexamples/valuesource/happybirthdaysong.h 2
In all other respects, property value sources are regular QML types. They must
be registered with the QML engine using the same macros as other types, and can
contain properties, signals and methods just like other types.
When a property value source object is assigned to a property, QML first tries
to assign it normally, as though it were a regular QML type. Only if this
assignment fails does the engine call the \l {QQmlPropertyValueSource::}{setTarget()} method. This allows
the type to also be used in contexts other than just as a value source.
\l {Extending QML - Property Value Source Example} shows the complete code used
to implement the \c HappyBirthdaySong property value source.
\section1 Optimization and Other Considerations
The \l{qml-engine-optimization}{ QML Engine} article suggests possible
optimization considerations as memory management and QVariant type usages.
*/
|