Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
definetypes.qdoc
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3/*!
4\page qtqml-cppintegration-definetypes.html
5\title Defining QML Types from C++
6\brief Description of ways to define QML object types from C++ code
7
8When extending QML with C++ code, a C++ class can be registered with the QML
9type system to enable the class to be used as a data type within QML code.
10While the properties, methods and signals of any QObject-derived class are
11accessible from QML, as discussed in \l{qtqml-cppintegration-exposecppattributes.html}
12{Exposing Attributes of C++ Types to QML}, such a class cannot be used as a
13data type from QML until it is registered with the type system. Additionally
14registration can provide other features, such as allowing a class to be used
15as an instantiable \l{qtqml-typesystem-objecttypes.html}{QML object type} from
16QML, or enabling a singleton instance of the class to be imported and used
17from QML.
18
19Additionally, the \l {Qt Qml} module provides mechanisms for implementing QML-specific
20features such as \e{attached properties} and \e{default properties} in C++.
21
22(Note that a number of the important concepts covered in this document are
23demonstrated in the \l{Writing QML Extensions with C++} tutorial.)
24
25\b{NOTE:} All headers that declare QML types need to be accessible without any prefix from the project's include path.
26
27For more information about C++ and the different QML integration methods,
28see the
29\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
30
31\section1 Registering C++ Types with the QML Type System
32
33A QObject-derived class can be registered with the QML type system to enable the
34type to be used as a data type from within QML code.
35
36The engine allows the registration of both instantiable and non-instantiable
37types. Registering an instantiable type enables a C++ class to be used as the
38definition of a QML object type, allowing it to be used in object declarations
39from QML code to create objects of this type. Registration also provides
40the engine with additional type metadata, enabling the type (and any enums
41declared by the class) to be used as a data type for property values, method
42parameters and return values, and signal parameters that are exchanged between
43QML and C++.
44
45Registering a non-instantiable type also registers the class as a data type in
46this manner, but the type cannot be used instantiated as a QML object type
47from QML. This is useful, for example, if a type has enums that should be
48exposed to QML but the type itself should not be instantiable.
49
50For a quick guide to choosing the correct approach to expose C++ types to QML,
51see \l {Choosing the Correct Integration Method Between C++ and QML}.
52
53\section2 Preconditions
54
55All the macros mentioned below are available from the \c qqmlregistration.h
56header. You need to add the following code to the files using them in order to
57make the macros available:
58
59\code
60#include <QtQml/qqmlregistration.h>
61\endcode
62
63Furthermore, your class declarations have to live in headers reachable via your
64project's include path. The declarations are used to generate registration code
65at compile time, and the registration code needs to include the headers that
66contain the declarations.
67
68\section2 Registering an Instantiable Object Type
69
70\b{Any QObject-derived C++ class can be registered as the definition of a
71\l{qtqml-typesystem-objecttypes.html}{QML object type}}. Once a
72class is registered with the QML type system, the class can be declared and
73instantiated like any other object type from QML code. Once created, a
74class instance can be manipulated from QML; as
75\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++
76Types to QML} explains, the properties, methods and signals of any
77QObject-derived class are accessible from QML code.
78
79To register a QObject-derived class as an instantiable QML object type, add
80\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration. You
81also need to make adjustments in the build system. For qmake, add
82\c {CONFIG += qmltypes}, a \c {QML_IMPORT_NAME}, and a
83\c QML_IMPORT_MAJOR_VERSION to your project file. For CMake, the file containing
84the class should be part of a target set-up with
85\l{qt_add_qml_module}{qt_add_qml_module()}.
86This will register the class into the type namespace under the given major version,
87using either the class name or an explicitly given name as QML type name. The
88minor version(s) will be derived from any revisions attached to properties,
89methods, or signals. The default minor version is \c 0. You can explicitly
90restrict the type to be available only from specific minor versions by adding
91the \c QML_ADDED_IN_VERSION() macro to the class declaration. Clients can
92import suitable versions of the namespace in order to use the type.
93
94For example, suppose there is a \c Message class with \c author and
95\c creationDate properties:
96
97\code
98class Message : public QObject
99{
100 Q_OBJECT
101 Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
102 Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
103 QML_ELEMENT
104public:
105 // ...
106};
107\endcode
108
109This type can be registered by adding an appropriate type namespace and version
110number to the project file. For example, to make the type available in the
111\c com.mycompany.messaging namespace with version 1.0:
112
113\if defined(onlinedocs)
114 \tab {build-qt-app}{tab-cmake}{CMake}{selected}
115 \tab {build-qt-app}{tab-qmake}{qmake}{}
116 \tabcontent {tab-cmake}
117 \else
118 \section3 Using CMake
119\endif
120 \badcode
121 qt_add_qml_module(messaging
122 URI com.mycompany.messaging
123 VERSION 1.0
124 SOURCES
125 message.cpp message.h
126 )
127 \endcode
128\if defined(onlinedocs)
129 \endtabcontent
130 \tabcontent {tab-qmake}
131\else
132 \section3 Using QMake
133\endif
134 \code
135 CONFIG += qmltypes
136 QML_IMPORT_NAME = com.mycompany.messaging
137 QML_IMPORT_MAJOR_VERSION = 1
138 \endcode
139
140 If the header the class is declared in is not accessible from your project's
141 include path, you may have to amend the include path so that the generated
142 registration code can be compiled.
143
144 \code
145 INCLUDEPATH += com/mycompany/messaging
146 \endcode
147\if defined(onlinedocs)
148 \endtabcontent
149\endif
150
151
152
153The type can be used in an \l{qtqml-syntax-basics.html#object-declarations}
154{object declaration} from QML, and its properties can be read and written to,
155as per the example below:
156
157\qml
158import com.mycompany.messaging
159
160Message {
161 author: "Amelie"
162 creationDate: new Date()
163}
164\endqml
165
166\section2 Registering Value Types
167
168Any type with a \l{Q_GADGET} macro can the registered as a
169\l{qtqml-typesystem-valuetypes.html}{QML value type}. Once such a type is
170registered with the QML type system it can be used as property type in QML
171code. Such an instance can be manipulated from QML; as
172\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++
173Types to QML} explains, the properties and methods of any value type are
174accessible from QML code.
175
176In contrast to object types, value types require \b{lower case} names. The
177preferred way to register them is using the \l{QML_VALUE_TYPE} or
178\l{QML_ANONYMOUS} macros. There is no equivalent to \l{QML_ELEMENT} as your
179C++ classes are typically going to have upper case names. Otherwise the
180registration is very similar to the registration of object types.
181
182For example, suppose you want to register a value type \c{person} that consists
183of two strings for first and last name:
184
185\code
186class Person
187{
188 Q_GADGET
189 Q_PROPERTY(QString firstName READ firstName WRITE setFirstName)
190 Q_PROPERTY(QString lastName READ lastName WRITE setLastName)
191 QML_VALUE_TYPE(person)
192public:
193 // ...
194};
195\endcode
196
197There are some further limitations on what you can do with value types:
198\list
199\li Value types cannot be singletons.
200\li Value types need to be default-constructible and copy-constructible.
201\li Using QProperty as a member of a value type is problematic. Value types get
202 copied, and you would need to decide what to do with any bindings on the
203 QProperty at that point. You should not use QProperty in value types.
204\li Value types cannot provide attached properties.
205\li The API to define extensions to value types (\l{QML_EXTENDED}) is not public
206 and subject to future changes.
207\endlist
208
209\section2 Value Types with Enumerations
210
211Exposing enumerations from a value type to QML requires some extra steps.
212
213Value types have lower case names in QML and types with lower case
214names are generally not addressable in JavaScript code (unless you specify
215\l{ValueTypeBehavior}{pragma ValueTypeBehavior: Addressable}). If you have
216a value type in C++ with an enumeration you want to expose to QML, you
217need to expose the enumeration separately.
218
219This can be solved by using \l{QML_FOREIGN_NAMESPACE}. First, derive from
220your value type to create a separate C++ type:
221
222\code
223class Person
224{
225 Q_GADGET
226 Q_PROPERTY(QString firstName READ firstName WRITE setFirstName)
227 Q_PROPERTY(QString lastName READ lastName WRITE setLastName)
228 QML_VALUE_TYPE(person)
229public:
230 enum TheEnum { A, B, C };
231 Q_ENUM(TheEnum)
232 //...
233};
234
235class PersonDerived: public Person
236{
237 Q_GADGET
238};
239\endcode
240
241Then expose the derived type as a foreign namespace:
242
243\code
244namespace PersonDerivedForeign
245{
246 Q_NAMESPACE
247 QML_NAMED_ELEMENT(Person)
248 QML_FOREIGN_NAMESPACE(PersonDerived)
249}
250\endcode
251
252This produces a \l{qtqml-typesystem-namespaces.html}{QML Namespace}
253called \c Person (upper case) with an enumeration called \c TheEnum and
254values \c{A}, \c{B}, and \c{C}. Then you can write the following in QML:
255
256\qml
257 someProperty: Person.A
258\endqml
259
260At the same time you can still use your value type called \c person
261(lower case) exactly as before.
262
263\section2 Registering Non-Instantiable Types
264
265Sometimes a QObject-derived class may need to be registered with the QML type
266system but not as an instantiable type. For example, this is the case if a C++
267class:
268
269\list
270\li is an interface type that should not be instantiable
271\li is a base class type that does not need to be exposed to QML
272\li declares some enum that should be accessible from QML, but otherwise should
273not be instantiable
274\li is a type that should be provided to QML through a singleton instance, and
275should not be instantiable from QML
276\endlist
277
278The \l {Qt Qml} module provides several macros for registering non-instantiable
279types:
280
281\list
282\li QML_ANONYMOUS registers a C++ type that is not instantiable and cannot be
283referred to from QML. This enables the engine to coerce any inherited types that
284are instantiable from QML.
285\li QML_INTERFACE registers an existing Qt interface type. The type is
286not instantiable from QML, and you cannot declare QML properties with it. Using
287C++ properties of this type from QML will do the expected interface casts,
288though.
289\li QML_UNCREATABLE(reason) combined with with QML_ELEMENT or QML_NAMED_ELEMENT
290registers a named C++ type that is not instantiable but should be identifiable
291as a type to the QML type system. This is useful if a type's enums or attached
292properties should be accessible from QML but the type itself should not be
293instantiable. The parameter should be an error message to be emitted if an
294attempt at creating an instance of the type is detected.
295\li QML_SINGLETON combined with QML_ELEMENT or QML_NAMED_ELEMENT registers a
296singleton type that can be imported from QML, as discussed below.
297\endlist
298
299Note that all C++ types registered with the QML type system must be
300QObject-derived, even if they are non-instantiable.
301
302
303\section3 Registering Singleton Objects with a Singleton Type
304
305A singleton type enables properties, signals and methods to be exposed in
306a namespace without requiring the client to manually instantiate an
307object instance. QObject singleton types in particular are an efficient and
308convenient way to provide functionality or global property values.
309
310Note that singleton types do not have an associated QQmlContext as they are
311shared across all contexts in an engine. QObject singleton type instances
312are constructed and owned by the QQmlEngine, and will be destroyed when
313the engine is destroyed.
314
315A QObject singleton type can be interacted with in a manner similar to any
316other QObject or instantiated type, except that only one (engine constructed
317and owned) instance will exist, and it must be referenced by type name rather
318than id. Q_PROPERTYs of QObject singleton types may be bound to, and Q_INVOKABLE
319functions of QObject module APIs may be used in signal handler expressions.
320This makes singleton types an ideal way to implement styling or theming, and
321they can also be used instead of ".pragma library" script imports to store global
322state or to provide global functionality.
323
324Once registered, a QObject singleton type may be imported and used like any
325other QObject instance exposed to QML. The following example assumes that
326a QObject singleton type was registered into the "MyThemeModule" namespace
327with version 1.0, where that QObject has a QColor "color" Q_PROPERTY:
328
329\qml
330import MyThemeModule 1.0 as Theme
331
332Rectangle {
333 color: Theme.color // binding.
334}
335\endqml
336
337A QJSValue may also be exposed as a singleton type, however clients should
338be aware that properties of such a singleton type cannot be bound to.
339
340See \l{QML_SINGLETON} for more information on how implement and
341register a new singleton type, and how to use an existing singleton type.
342See \l{Singletons in QML} for more in-depth information about singletons.
343
344\note Enum values for registered types in QML should start with a capital.
345
346\section2 Final properties
347
348Properties declared final using the \c FINAL modifier to \l Q_PROPERTY cannot
349be overridden. This means that any properties or functions of the same name,
350declared either in QML or in C++ on derived types, are ignored by the QML
351engine. You should declare properties \c FINAL when possible, in order to avoid
352accidental overrides. An override of a property is visible not only in
353derived classes, but also to QML code executing the context of the base class.
354Such QML code, typically expects the original property, though. This is a
355frequent source of mistakes.
356
357Properties declared \c FINAL can also not be overridden by functions in QML, or
358by \l Q_INVOKABLE methods in C++.
359
360\section2 Type Revisions and Versions
361
362Many of the type registration functions require versions to be specified
363for the registered type. Type revisions and versions allow new properties
364or methods to exist in the new version while remaining compatible with
365previous versions.
366
367Consider these two QML files:
368\code
369// main.qml
370import QtQuick 1.0
371
372Item {
373 id: root
374 MyType {}
375}
376\endcode
377
378\code
379// MyType.qml
380import MyTypes 1.0
381
382CppType {
383 value: root.x
384}
385\endcode
386
387where \c CppType maps to the C++ class \c CppType.
388
389If the author of CppType adds a \c root property to CppType in a new
390version of their type definition, \c root.x now resolves to a different value
391because \c root is also the \c id of the top level component. The author could
392specify that the new \c root property is available from a specific minor
393version. This permits new properties and features to be added to existing
394types without breaking existing programs.
395
396The REVISION tag is used to mark the \c root property as added in revision 1
397of the type. Methods such as Q_INVOKABLE's, signals and slots can also be
398tagged for a revision using the \c Q_REVISION(x) macro:
399
400\code
401class CppType : public BaseType
402{
403 Q_OBJECT
404 Q_PROPERTY(int root READ root WRITE setRoot NOTIFY rootChanged REVISION 1)
405 QML_ELEMENT
406
407signals:
408 Q_REVISION(1) void rootChanged();
409};
410\endcode
411
412The revisions given this way are automatically interpreted as minor versions to
413the major version given in the project file. In this case, \c root is only
414available when \c MyTypes version 1.1 or higher is imported. Imports of
415\c MyTypes version 1.0 remain unaffected.
416
417For the same reason, new types introduced in later versions should be tagged
418with the QML_ADDED_IN_VERSION macro.
419
420This feature of the language allows for behavioural changes to be made
421without breaking existing applications. Consequently QML module authors
422should always remember to document what changed between minor versions, and
423QML module users should check that their application still runs correctly
424before deploying an updated import statement.
425
426Revisions of a base class that your type depends upon are automatically
427registered when registering the type itself. This is useful when deriving
428from base classes provided by other authors, e.g. when extending classes from
429the Qt Quick module.
430
431\note The QML engine does not support revisions for properties or signals of
432grouped and attached property objects.
433
434\section2 Registering Extension Objects
435
436When integrating existing classes and technology into QML, APIs will
437often need tweaking to fit better into the declarative environment.
438Although the best results are usually obtained by modifying the original
439classes directly, if this is either not possible or is complicated by some
440other concerns, extension objects allow limited extension possibilities
441without direct modifications.
442
443\e{Extension objects} add additional properties to an existing type. An extended
444type definition allows the programmer to supply an additional type, known as the
445\e{extension type}, when registering the class. Its members are transparently
446merged with the original target class when used from within QML. For example:
447
448\qml
449QLineEdit {
450 leftMargin: 20
451}
452\endqml
453
454The \c leftMargin property is a new property added to an existing C++ type, \l
455QLineEdit, without modifying its source code.
456
457The QML_EXTENDED(extension) macro is for registering extended types. The
458argument is the name of another class to be used as extension.
459
460You can also use QML_EXTENDED_NAMESPACE(namespace) to register a namespace, and
461especially the enumerations declared within, as an extension to a type. If the
462type you are extending is itself a namespace, you need to use
463QML_NAMESPACE_EXTENDED(namespace) instead.
464
465An extension class is a regular QObject, with a constructor that takes a QObject
466pointer. However, the extension class creation is delayed until the first
467extended property is accessed. The extension class is created and the target
468object is passed in as the parent. When the property on the original is
469accessed, the corresponding property on the extension object is used instead.
470
471\section2 Registering Foreign Types
472
473There may be C++ types that cannot be modified to hold the above mentioned
474macros. Those may be types from 3rdparty libraries, or types that need to
475fulfill some contract that contradicts the presence of those macros. You can
476still expose those types to QML, though, using the QML_FOREIGN macro. In order
477to do this, create a separate struct that consists entirely of the registration
478macros, like this:
479
480\code
481// Contains class Immutable3rdParty
482#include <3rdpartyheader.h>
483
484struct Foreign
485{
486 Q_GADGET
487 QML_FOREIGN(Immutable3rdParty)
488 QML_NAMED_ELEMENT(Accessible3rdParty)
489 QML_ADDED_IN_VERSION(2, 4)
490 // QML_EXTENDED, QML_SINGLETON ...
491};
492\endcode
493
494From this code, you get a QML type with the methods and properties of
495Immutable3rdParty, and the QML traits (e.g.: singleton, extended) specified in
496Foreign.
497
498\section1 Defining QML-Specific Types and Attributes
499
500\section2 Providing Attached Properties
501\keyword Integrating QML and C++ - Attached Properties
502
503In the QML language syntax, there is a notion of \l{Attached properties and
504attached signal handlers}{\e {attached properties} and \e {attached signal
505handlers}}, which are additional attributes that are attached to an object.
506Essentially, such attributes are implemented and provided by an \e {attaching
507type}, and these attributes may be \e attached to an object of another type.
508This contrasts with ordinary object properties which are provided by the object
509type itself (or the object's inherited type).
510
511For example, the \l Item below uses attached properties and attached handlers:
512
513\qml
514import QtQuick 2.0
515
516Item {
517 width: 100; height: 100
518
519 focus: true
520 Keys.enabled: false
521 Keys.onReturnPressed: console.log("Return key was pressed")
522}
523\endqml
524
525Here, the \l Item object is able to access and set the values of \c Keys.enabled
526and \c Keys.onReturnPressed. This allows the \l Item object to access these
527extra attributes as an extension to its own existing attributes.
528
529\section3 Steps for Implementing Attached Objects
530
531When considering the above example, there are several parties involved:
532
533\list
534\li There is an instance of an anonymous \e {attached object type}, with
535an \c enabled and a \c returnPressed signal, that has been attached to the
536\l Item object to enable it to access and set these attributes.
537\li The \l Item object is the \e {attachee}, to which the instance of the \e
538{attached object type} has been attached.
539\li \l Keys is the \e {attaching type}, which provides the \e {attachee} with a
540named qualifier, "Keys", through which it may access the attributes of the
541\e {attached object type}.
542\endlist
543
544When the QML engine processes this code, it creates a single instance of the
545\e {attached object type} and attaches this instance to the \l Item object,
546thereby providing it with access to the \c enabled and \c returnPressed
547attributes of the instance.
548
549The mechanisms for providing attached objects can be implemented from C++ by
550providing classes for the \e {attached object type} and \e {attaching type}.
551For the \e{attached object type}, provide a QObject-derived class that defines
552the attributes to be made accessible to \e attachee objects. For the
553\e {attaching type}, provide a QObject-derived class that:
554
555\list
556\li implements a static qmlAttachedProperties() with the following signature:
557 \code
558 static <AttachedPropertiesType> *qmlAttachedProperties(QObject *object);
559 \endcode
560
561 This method should return an instance of the \e{attached object type}.
562
563 The QML engine invokes this method in order to attach an instance of
564 the attached object type to the \e attachee specified by the \c object
565 parameter. It is customary, though not strictly required, for this method
566 implementation to parent the returned instance to \c object in order
567 to prevent memory leaks.
568
569 This method is called at most once by the engine for each attachee object
570 instance, as the engine caches the returned instance pointer for subsequent
571 attached property accesses. Consequently the attachment object may not be
572 deleted until the attachee \c object is destroyed.
573
574\li is declared as an attaching type, by adding the QML_ATTACHED(attached) macro
575 to the class declaration. The argument is the name of the
576 \e{attached object type}
577\endlist
578
579
580\section3 Implementing Attached Objects: An Example
581
582For example, take the \c Message type described in an \l{Registering an
583Instantiable Object Type}{earlier example}:
584
585\code
586class Message : public QObject
587{
588 Q_OBJECT
589 Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
590 Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
591 QML_ELEMENT
592public:
593 // ...
594};
595\endcode
596
597Suppose it is necessary to trigger a signal on a \c Message when it is
598published to a message board, and also track when the message has expired on
599the message board. Since it doesn't make sense to add these attributes
600directly to a \c Message, as the attributes are more relevant to the message
601board context, they could be implemented as \e attached attributes on a
602\c Message object that are provided through a "MessageBoard" qualifier. In
603terms of the concepts described earlier, the parties involved here are:
604
605\list
606\li An instance of an anonymous \e{attached object type}, which provides a
607 \c published signal and an expired property. This type is implemented by
608 \c MessageBoardAttachedType below
609\li A \c Message object, which will be the \e attachee
610\li The \c MessageBoard type, which will be the \e {attaching type} that is
611 used by \c Message objects to access the attached attributes
612\endlist
613
614Following is an example implementation. First, there needs to be an
615\e {attached object type} with the necessary properties and signals that
616will be accessible to the \e attachee:
617
618\code
619class MessageBoardAttachedType : public QObject
620{
621 Q_OBJECT
622 Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged)
623 QML_ANONYMOUS
624public:
625 MessageBoardAttachedType(QObject *parent);
626 bool expired() const;
627 void setExpired(bool expired);
628signals:
629 void published();
630 void expiredChanged();
631};
632\endcode
633
634Then the \e {attaching type}, \c MessageBoard, must declare a \c
635qmlAttachedProperties() method that returns an instance of the
636\e {attached object type} as implemented by MessageBoardAttachedType.
637Additionally, \c MessageBoard must be declared as an attaching type
638via the QML_ATTACHED() macro:
639
640\code
641class MessageBoard : public QObject
642{
643 Q_OBJECT
644 QML_ATTACHED(MessageBoardAttachedType)
645 QML_ELEMENT
646public:
647 static MessageBoardAttachedType *qmlAttachedProperties(QObject *object)
648 {
649 return new MessageBoardAttachedType(object);
650 }
651};
652\endcode
653
654Now, a \c Message type can access the properties and signals of the attached
655object type:
656
657\qml
658Message {
659 author: "Amelie"
660 creationDate: new Date()
661
662 MessageBoard.expired: creationDate < new Date("January 01, 2015 10:45:00")
663 MessageBoard.onPublished: console.log("Message by", author, "has been
664published!")
665}
666\endqml
667
668Additionally, the C++ implementation may access the attached object instance
669that has been attached to any object by calling the
670qmlAttachedPropertiesObject() function.
671
672For example:
673
674\code
675Message *msg = someMessageInstance();
676MessageBoardAttachedType *attached =
677 qobject_cast<MessageBoardAttachedType*>(qmlAttachedPropertiesObject<MessageBoard>(msg));
678
679qDebug() << "Value of MessageBoard.expired:" << attached->expired();
680\endcode
681
682
683\section3 Propagating Attached Properties
684
685\l QQuickAttachedPropertyPropagator can be subclassed to propagate attached properties
686from a parent object to its children, similar to \l {Control::}{font} and
687\l {Item::}{palette} propagation. It supports propagation through
688\l {Item}{items}, \l {Popup}{popups}, and \l {Window}{windows}.
689
690
691\section2 Property Modifier Types
692
693A property modifier type is a special kind of QML object type. A property
694modifier type instance affects a property (of a QML object instance) which it
695is applied to. There are two different kinds of property modifier types:
696\list
697\li property value write interceptors
698\li property value sources
699\endlist
700
701A property value write interceptor can be used to filter or modify values as
702they are written to properties. Currently, the only supported property
703value write interceptor is the \l Behavior type provided by the \c QtQuick
704import.
705
706A property value source can be used to automatically update the value of a
707property over time. Clients can define their own property value source types.
708The various \l{qtquick-statesanimations-animations.html}{property animation}
709types provided by the \c QtQuick import are examples of property value
710sources.
711
712Property modifier type instances can be created and applied to a property of
713a QML object through the "<ModifierType> on <propertyName>" syntax, as the
714following example shows:
715
716\qml
717import QtQuick 2.0
718
719Item {
720 width: 400
721 height: 50
722
723 Rectangle {
724 width: 50
725 height: 50
726 color: "red"
727
728 NumberAnimation on x {
729 from: 0
730 to: 350
731 loops: Animation.Infinite
732 duration: 2000
733 }
734 }
735}
736\endqml
737
738This is commonly referred to as "on" syntax.
739
740Clients can register their own property value source types, but currently not
741property value write interceptors.
742
743\section3 Property Value Sources
744
745\e {Property value sources} are QML types that can automatically update the
746value of a property over time, using the
747\c {<PropertyValueSource> on <property>} syntax. For example, the various
748\l{qtquick-statesanimations-animations.html}{property animation} types
749provided by the \c QtQuick module are examples of property value sources.
750
751A property value source can be implemented in C++ by subclassing
752QQmlPropertyValueSource and providing an implementation that writes different
753values to a property over time. When the property value source is applied to a
754property using the \c {<PropertyValueSource> on <property>} syntax in QML, it
755is given a reference to this property by the engine so that the property value
756can be updated.
757
758For example, suppose there is a \c RandomNumberGenerator class to be made
759available as a property value source, so that when applied to a QML property,
760it will update the property value to a different random number every 500
761milliseconds. Additionally, a maxValue can be provided to this random number
762generator. This class can be implemented as follows:
763
764\code
765class RandomNumberGenerator : public QObject, public QQmlPropertyValueSource
766{
767 Q_OBJECT
768 Q_INTERFACES(QQmlPropertyValueSource)
769 Q_PROPERTY(int maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged);
770 QML_ELEMENT
771public:
772 RandomNumberGenerator(QObject *parent)
773 : QObject(parent), m_maxValue(100)
774 {
775 QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(updateProperty()));
776 m_timer.start(500);
777 }
778
779 int maxValue() const;
780 void setMaxValue(int maxValue);
781
782 virtual void setTarget(const QQmlProperty &prop) { m_targetProperty = prop; }
783
784signals:
785 void maxValueChanged();
786
787private slots:
788 void updateProperty() {
789 m_targetProperty.write(QRandomGenerator::global()->bounded(m_maxValue));
790 }
791
792private:
793 QQmlProperty m_targetProperty;
794 QTimer m_timer;
795 int m_maxValue;
796};
797\endcode
798
799When the QML engine encounters a use of \c RandomNumberGenerator as a property
800value source, it invokes \c RandomNumberGenerator::setTarget() to provide the
801type with the property to which the value source has been applied. When the
802internal timer in \c RandomNumberGenerator triggers every 500 milliseconds,
803it will write a new number value to that specified property.
804
805Once the \c RandomNumberGenerator class has been registered with the QML type
806system, it can be used from QML as a property value source. Below, it is used
807to change the width of a \l Rectangle every 500 milliseconds:
808
809\qml
810import QtQuick 2.0
811
812Item {
813 width: 300; height: 300
814
815 Rectangle {
816 RandomNumberGenerator on width { maxValue: 300 }
817
818 height: 100
819 color: "red"
820 }
821}
822\endqml
823
824In all other respects, property value sources are regular QML types that can
825have properties, signals methods and so on, but with the added capability that
826they can be used to change property values using the
827\c {<PropertyValueSource> on <property>} syntax.
828
829When a property value source object is assigned to a property, QML first tries
830to assign it normally, as though it were a regular QML type. Only if this
831assignment fails does the engine call the \l
832{QQmlPropertyValueSource::}{setTarget()} method. This allows
833the type to also be used in contexts other than just as a value source.
834
835
836\section2 Specifying Default and Parent Properties for QML Object Types
837
838Any QObject-derived type that is registered as an instantiable QML object type
839can optionally specify a \e {default property} for the type. A default
840property is the property to which an object's children are automatically
841assigned if they are not assigned to any specific property.
842
843The default property can be set by calling the Q_CLASSINFO() macro for a class
844with a specific "DefaultProperty" value. For example, the \c MessageBoard
845class below specifies its \c messages property as the default property for the
846class:
847
848\code
849class MessageBoard : public QObject
850{
851 Q_OBJECT
852 Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
853 Q_CLASSINFO("DefaultProperty", "messages")
854 QML_ELEMENT
855public:
856 QQmlListProperty<Message> messages();
857
858private:
859 QList<Message *> m_messages;
860};
861\endcode
862
863This enables children of a \c MessageBoard object to be automatically assigned
864to its \c messages property if they are not assigned to a specific property. For
865example:
866
867\qml
868MessageBoard {
869 Message { author: "Naomi" }
870 Message { author: "Clancy" }
871}
872\endqml
873
874If \c messages was not set as the default property, then any \c Message objects
875would have to be explicitly assigned to the \c messages property instead, as
876follows:
877
878\qml
879MessageBoard {
880 messages: [
881 Message { author: "Naomi" },
882 Message { author: "Clancy" }
883 ]
884}
885\endqml
886
887(Incidentally, the \l Item::data property is its default property. Any \l Item
888objects added to this \c data property are also added to the list of
889\l Item::children, so the use of the default property enables visual children
890to be declared for an item without explicitly assigning them to the
891\l{Item::}{children} property.)
892
893Additionally, you can declare a "ParentProperty" Q_CLASSINFO() to inform the QML
894engine which property should denote the parent object in the QML hierarchy. For
895example, the Message type might be declared as follows:
896
897\code
898class Message : public QObject
899{
900 Q_OBJECT
901 Q_PROPERTY(QObject* board READ board BINDABLE boardBindable)
902 Q_PROPERTY(QString author READ author BINDABLE authorBindable)
903 Q_CLASSINFO("ParentProperty", "board")
904 QML_ELEMENT
905
906public:
907 Message(QObject *parent = nullptr) : QObject(parent) { m_board = parent; }
908
909 QObject *board() const { return m_board.value(); }
910 QBindable<QObject *> boardBindable() { return QBindable<QObject *>(&m_board); }
911
912 QString author() const { return m_author.value(); }
913 QBindable<QString> authorBindable() { return QBindable<QString>(&m_author); }
914
915private:
916 QProperty<QObject *> m_board;
917 QProperty<QString> m_author;
918};
919\endcode
920
921Defining the parent property affords \l qmllint and other tools better insight
922into the intention of your code and avoids false positive warnings on some
923property accesses.
924
925\section2 Defining Visual Items with the Qt Quick Module
926
927When building user interfaces with the \l {Qt Quick} module, all QML objects that are
928to be visually rendered must derive from the \l Item type, as it is the base
929type for all visual objects in \l {Qt Quick}. This \l Item type is
930implemented by the QQuickItem C++ class, which is provided by the
931\l {Qt Quick} module. Therefore, this class should be subclassed when it is
932necessary to implement a visual type in C++ that can be integrated into a
933QML-based user interface.
934
935See the QQuickItem documentation for more information. Additionally, the
936\l{Writing QML Extensions with C++} tutorial demonstrates how a QQuickItem-based
937visual item can be implemented in C++ and integrated into a Qt Quick-based user
938interface.
939
940
941\section1 Receiving Notifications for Object Initialization
942
943For some custom QML object types, it may be beneficial to delay the
944initialization of particular data until the object has been created and all of
945its properties have been set. For example, this may be the case if the
946initialization is costly, or if the initialization should not be performed until
947all property values have been initialized.
948
949The \l {Qt Qml} module provides the QQmlParserStatus to be subclassed for these
950purposes. It defines a number of virtual methods that are invoked at
951various stages during component instantiation. To receive these notifications, a
952C++ class should inherit QQmlParserStatus and also notify the Qt meta system
953using the Q_INTERFACES() macro.
954
955For example:
956
957\code
958class MyQmlType : public QObject, public QQmlParserStatus
959{
960 Q_OBJECT
961 Q_INTERFACES(QQmlParserStatus)
962 QML_ELEMENT
963public:
964 virtual void componentComplete()
965 {
966 // Perform some initialization here now that the object is fully created
967 }
968};
969\endcode
970
971*/