1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
4\page qtqml-cppintegration-exposecppattributes.html
5\title Exposing Attributes of C++ Types to QML
6\brief Description of how to expose the attributes of a C++ type to QML
8QML can easily be extended with functionality defined in C++ code. Due to the
9tight integration of the QML engine with the \l{The Meta-Object System}{Qt
10meta-object system}, any functionality that is appropriately exposed by a
11QObject-derived class or a Q_GADGET type is accessible from QML code. This
12enables C++ data and functions to be accessible directly from QML, often with
13little or no modification.
15The QML engine has the ability to introspect QObject instances through the
16meta-object system. This means any QML code can access the following members of
17an instance of a QObject-derived class:
21\li Methods (providing they are public slots or flagged with Q_INVOKABLE)
25(Additionally, enums are available if they have been declared with Q_ENUM.
26See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
29In general, these are accessible from QML regardless of whether a
30QObject-derived class has been \l{Registering C++ types with the QML type
31system}{registered with the QML type system}. However, if a class is to be
32used in a way that requires the engine to access additional type information
33— for example, if the class itself is to be used as a method parameter or
34property, or if one of its enum types is to be used in this way — then the
35class may need to be registered. Registration is recommended for all types you
36use in QML, as only registered types can be analyzed at compile time.
38Registration is required for Q_GADGET types, as they don't derive from a known
39common base and can't be made available automatically. Without registration,
40their properties and methods are inaccessible.
42You can make C++ types from a different module available in your own module by
43adding a dependency to your \l{qt_add_qml_module} call using the \e DEPENDENCIES
44option. You may, for example, want to depend on QtQuick so that your QML-exposed
45C++ types can use \l QColor as method arguments and return values. QtQuick
46exposes \l QColor as a \l {QML Value Types}{value type} \e color. Such
47dependencies may be automatically inferred at run time, but you should not rely
50Also note that a number of the important concepts covered in this document are
51demonstrated in the \l{Writing QML Extensions with C++} tutorial.
53For more information about C++ and the different QML integration methods,
55\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
57\section1 Data Type Handling and Ownership
59Any data that is transferred from C++ to QML, whether as a property value, a
60method parameter or return value, or a signal parameter value, must be of a
61type that is supported by the QML engine.
63By default, the engine supports a number of Qt C++ types and can automatically
64convert them as appropriately when used from QML. Additionally, C++ classes
65that are \l{Registering C++ types with the QML type system}{registered} with
66the QML type system can be used as data types, as can their enums if
67appropriately registered. See \l{qtqml-cppintegration-data.html}{Data Type
68Conversion Between QML and C++} for further information.
70Additionally, data ownership rules are taken into consideration when data is
71transferred from C++ to QML. See \l {Data Ownership} for more details.
74\section1 Exposing Properties
76A \e property can be specified for any QObject-derived class using the
77Q_PROPERTY() macro. A property is a class data member with an associated read
78function and optional write function.
80All properties of a QObject-derived or Q_GADGET class are accessible from QML.
82For example, below is a \c Message class with an \c author property. As
83specified by the Q_PROPERTY macro call, this property is readable through
84the \c author() method, and writable through the \c setAuthor() method:
86\note Do not use \e typedef or \e using for Q_PROPERTY types as these
87will confuse moc. This may make certain type comparisons fail.
92using FooEnum = Foo::Enum;
94class Bar : public QObject
97 Q_PROPERTY(FooEnum enum READ enum WRITE setEnum NOTIFY enumChanged)
101Refer to the type directly:
104class Bar : public QObject
107 Q_PROPERTY(Foo::Enum enum READ enum WRITE setEnum NOTIFY enumChanged)
111In order to make \c Message available you need to use \l{QML_ELEMENT} in C++
112and \l{qt_add_qml_module} in CMake.
115class Message : public QObject
119 Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
121 void setAuthor(const QString &a)
125 emit authorChanged();
129 QString author() const
135 void authorChanged();
142An instance of \c Message can be passed as required property to a file called
143\c MyItem.qml to make it available:
146 int main(int argc, char *argv[]) {
147 QGuiApplication app(argc, argv);
151 view.setInitialProperties({{"msg", &msg}});
152 view.setSource(QUrl::fromLocalFile("MyItem.qml"));
159Then, the \c author property could be read from \c MyItem.qml:
166 required property Message msg
168 width: 100; height: 100
169 text: msg.author // invokes Message::author() to get this value
171 Component.onCompleted: {
172 msg.author = "Jonah" // invokes Message::setAuthor()
177For maximum interoperability with QML, \b {any property that is writable should
178have an associated NOTIFY signal} that is emitted whenever the property value
179has changed. This allows the property to be used with \l{Property
180Binding}{property binding}, which is an essential feature of QML that enforces
181relationships between properties by automatically updating a property whenever
182any of its dependencies change in value.
184In the above example, the associated NOTIFY signal for the \c author property is
185\c authorChanged, as specified in the Q_PROPERTY() macro call. This means that
186whenever the signal is emitted — as it is when the author changes
187in Message::setAuthor() — this notifies the QML engine that any
188bindings involving the \c author property must be updated, and in turn, the
189engine will update the \c text property by calling \c Message::author() again.
191If the \c author property was writable but did not have an associated NOTIFY
192signal, the \c text value would be initialized with the initial value returned
193by \c Message::author() but would not be updated with any later changes to this
194property. In addition, any attempts to bind to the property from QML will
195produce a runtime warning from the engine.
197\note It is recommended that the NOTIFY signal be named \e <property>Changed
198where \c <property> is the name of the property. The associated property
199change signal handler generated by the QML engine will always take the form
200\c on<Property>Changed, regardless of the name of the related C++ signal, so
201it is recommended that the signal name follows this convention to avoid any
205\section3 Notes on Use of Notify Signals
207To prevent loops or excessive evaluation, developers should ensure that the
208property change signal is only emitted when the property value has actually
209changed. Also, if a property or group of properties is infrequently used, it
210is permitted to use the same NOTIFY signal for several properties. This should
211be done with care to ensure that performance doesn't suffer.
213The presence of a NOTIFY signal does incur a small overhead. There are cases
214where a property's value is set at object construction time, and does not
215subsequently change. The most common case of this is when a type uses \l
216{Grouped Properties}, and the grouped property object is allocated once, and
217only freed when the object is deleted. In these cases, the CONSTANT
218attribute may be added to the property declaration instead of a NOTIFY
221The CONSTANT attribute should only be used for properties whose value is set,
222and finalized, only in the class constructor. All other properties that want
223to be used in bindings should have a NOTIFY signal instead.
226\section2 Properties with Object Types
228Object-type properties are accessible from QML providing that the object type
229has been appropriately \l{Registering C++ types with the QML type
230system}{registered} with the QML type system.
232For example, the \c Message type might have a \c body property of type
236class Message : public QObject
239 Q_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged)
241 MessageBody* body() const;
242 void setBody(MessageBody* body);
245class MessageBody : public QObject
248 Q_PROPERTY(QString text READ text WRITE text NOTIFY textChanged)
253Suppose the \c Message type was \l{Registering C++ types with the QML type
254system}{registered} with the QML type system, allowing it to be used as an
255object type from QML code:
263If the \c MessageBody type was also registered with the type system, it would be
264possible to assign \c MessageBody to the \c body property of a \c Message, all
270 text: "Hello, world!"
276\section2 Properties with Object-List Types
278Properties containing lists of QObject-derived types can also be exposed to
279QML. For this purpose, however, one should use QQmlListProperty rather than
280QList<T> as the property type. This is because QList is not a QObject-derived
281type, and so cannot provide the necessary QML property characteristics
282through the Qt meta object system, such as signal notifications when a list
285For example, the \c MessageBoard class below has a \c messages property of
286type QQmlListProperty that stores a list of \c Message instances:
289class MessageBoard : public QObject
292 Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
294 QQmlListProperty<Message> messages();
297 static void append_message(QQmlListProperty<Message> *list, Message *msg);
299 QList<Message *> m_messages;
303The MessageBoard::messages() function simply creates and returns a
304QQmlListProperty from its QList<T> \c m_messages member, passing the
305appropriate list modification functions as required by the QQmlListProperty
309QQmlListProperty<Message> MessageBoard::messages()
311 return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message);
314void MessageBoard::append_message(QQmlListProperty<Message> *list, Message *msg)
316 MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object);
318 msgBoard->m_messages.append(msg);
322Note that the template class type for the QQmlListProperty — in this case,
323\c Message — must be \l{Registering C++ types with the QML type system}
324{registered} with the QML type system.
327\section2 Grouped Properties
328\keyword Integrating QML and C++ - Grouped Properties
330Any read-only object-type property is accessible from QML code as a
331\e {grouped property}. This can be used to expose a group of related
332properties that describe a set of attributes for a type.
334For example, suppose the \c Message::author property was of type
335\c MessageAuthor rather than a simple string, with sub-properties
336of \c name and \c email:
339class MessageAuthor : public QObject
341 Q_PROPERTY(QString name READ name WRITE setName)
342 Q_PROPERTY(QString email READ email WRITE setEmail)
347class Message : public QObject
350 Q_PROPERTY(MessageAuthor* author READ author)
352 Message(QObject *parent)
353 : QObject(parent), m_author(new MessageAuthor(this))
356 MessageAuthor *author() const {
360 MessageAuthor *m_author;
364The \c author property could be written to using the
365\l{qtqml-syntax-objectattributes.html#grouped-properties}{grouped property
371 author.name: "Alexandra"
372 author.email: "alexandra@mail.com"
376A type that is exposed as a grouped property differs from an \l{Properties with
377Object Types}{object-type property} in that the grouped property is read-only,
378and is initialized to a valid value by the parent object at construction. The
379grouped property's sub-properties may be modified from QML but the grouped
380property object itself will never change, whereas an object-type property may be
381assigned a new object value from QML at any time. Thus, the lifetime of a
382grouped property object is controlled strictly by the C++ parent
383implementation, whereas an object-type property can be freely created and
384destroyed through QML code.
387\section1 Exposing Methods (Including Qt Slots)
389Any method of a QObject-derived type is accessible from QML code if it is:
392\li A public method flagged with the Q_INVOKABLE() macro
393\li A method that is a public Qt \l{Signals & Slots}{slot}
396For example, the \c MessageBoard class below has a \c postMessage() method that
397has been flagged with the Q_INVOKABLE macro, as well as a \c refresh() method
398that is a public slot:
401 class MessageBoard : public QObject
407 Q_INVOKABLE bool postMessage(const QString &msg) {
408 qDebug() << "Called the C++ method with" << msg;
414 qDebug() << "Called the C++ slot";
419If an instance of \c MessageBoard was set as the required property for a file \c
420MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
428 int main(int argc, char *argv[]) {
429 QGuiApplication app(argc, argv);
431 MessageBoard msgBoard;
433 view.setInitialProperties({{"msgBoard", &msgBoard}});
434 view.setSource(QUrl::fromLocalFile("MyItem.qml"));
448 required property MessageBoard msgBoard
450 width: 100; height: 100
455 var result = msgBoard.postMessage("Hello from QML")
456 console.log("Result of postMessage():", result)
464If a C++ method has a parameter with a \c QObject* type, the parameter value
465can be passed from QML using an object \c id or a JavaScript \l var value
466that references the object.
468QML supports the calling of overloaded C++ functions. If there are multiple C++
469functions with the same name but different arguments, the correct function will
470be called according to the number and the types of arguments that are provided.
472Values returned from C++ methods are converted to JavaScript values when
473accessed from JavaScript expressions in QML.
475\section2 C++ methods and the 'this' object
477You may want to retrieve a C++ method from one object and call it on a different
478object. Consider the following example, within a QML module called \c{Example}:
485class Invokable : public QObject
490 Invokable(QObject *parent = nullptr) : QObject(parent) {}
492 Q_INVOKABLE void invoke() { qDebug() << "invoked on " << objectName(); }
504 property Invokable child: Invokable {}
505 Component.onCompleted: child.invoke.call(this)
510If you load the QML code from a suitable main.cpp, it should print
511"invoked on parent". However, due to a long standing bug, it doesn't.
512Historically, the 'this' object of C++-based methods is inseparably bound to
513the method. Changing this behavior for existing code would cause subtle errors
514since the 'this' object is implicit in many places. Since Qt 6.5 you can
515explicitly opt into the correct behavior and allow C++ methods to accept a
516'this' object. To do so, add the following pragma to your QML documents:
519pragma NativeMethodBehavior: AcceptThisObject
522With this line added, the example above will work as expected.
524\section1 Exposing Signals
526Any public \l{Signals & Slots}{signal} of a QObject-derived type is accessible
529The QML engine automatically creates a \l{Signal and Handler Event
530System}{signal handler} for any signal of a QObject-derived type that is used
531from QML. Signal handlers are always named \e on<Signal> where \c <Signal> is
532the name of the signal, with the first letter capitalized. All parameters passed
533by the signal are available in the signal handler through the parameter names.
535For example, suppose the \c MessageBoard class has a \c newMessagePosted()
536signal with a single parameter, \c subject:
539 class MessageBoard : public QObject
545 void newMessagePosted(const QString &subject);
549If the \c MessageBoard type was \l{Registering C++ types with the QML type
550system}{registered} with the QML type system, then a \c MessageBoard object
551declared in QML could receive the \c newMessagePosted() signal using a signal
552handler named \c onNewMessagePosted, and examine the \c subject parameter
557 onNewMessagePosted: (subject)=> console.log("New message received:", subject)
561As with property values and method parameters, a signal parameter must have a
562type that is supported by the QML engine; see
563\l {Data Type Conversion Between QML and C++}. (Using an
564unregistered type will not generate an error, but the parameter value will
565not be accessible from the handler.)
567Classes may have multiple signals with the same name, but only the final
568signal is accessible as a QML signal. Note that signals with the same name
569but different parameters cannot be distinguished from one another.