Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
exposecppattributes.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-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
7
8
QML can easily be extended with functionality defined in C++ code. Due to the
9
tight integration of the QML engine with the \l{The Meta-Object System}{Qt
10
meta-object system}, any functionality that is appropriately exposed by a
11
QObject-derived class or a Q_GADGET type is accessible from QML code. This
12
enables C++ data and functions to be accessible directly from QML, often with
13
little or no modification.
14
15
The QML engine has the ability to introspect QObject instances through the
16
meta-object system. This means any QML code can access the following members of
17
an instance of a QObject-derived class:
18
19
\list
20
\li Properties
21
\li Methods (providing they are public slots or flagged with Q_INVOKABLE)
22
\li Signals
23
\endlist
24
25
(Additionally, enums are available if they have been declared with Q_ENUM.
26
See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
27
for more details.)
28
29
In general, these are accessible from QML regardless of whether a
30
QObject-derived class has been \l{Registering C++ types with the QML type
31
system}{registered with the QML type system}. However, if a class is to be
32
used 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
34
property, or if one of its enum types is to be used in this way — then the
35
class may need to be registered. Registration is recommended for all types you
36
use in QML, as only registered types can be analyzed at compile time.
37
38
Registration is required for Q_GADGET types, as they don't derive from a known
39
common base and can't be made available automatically. Without registration,
40
their properties and methods are inaccessible.
41
42
You can make C++ types from a different module available in your own module by
43
adding a dependency to your \l{qt_add_qml_module} call using the \e DEPENDENCIES
44
option. You may, for example, want to depend on QtQuick so that your QML-exposed
45
C++ types can use \l QColor as method arguments and return values. QtQuick
46
exposes \l QColor as a \l {QML Value Types}{value type} \e color. Such
47
dependencies may be automatically inferred at run time, but you should not rely
48
on this.
49
50
Also note that a number of the important concepts covered in this document are
51
demonstrated in the \l{Writing QML Extensions with C++} tutorial.
52
53
For more information about C++ and the different QML integration methods,
54
see the
55
\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
56
57
\section1 Data Type Handling and Ownership
58
59
Any data that is transferred from C++ to QML, whether as a property value, a
60
method parameter or return value, or a signal parameter value, must be of a
61
type that is supported by the QML engine.
62
63
By default, the engine supports a number of Qt C++ types and can automatically
64
convert them as appropriately when used from QML. Additionally, C++ classes
65
that are \l{Registering C++ types with the QML type system}{registered} with
66
the QML type system can be used as data types, as can their enums if
67
appropriately registered. See \l{qtqml-cppintegration-data.html}{Data Type
68
Conversion Between QML and C++} for further information.
69
70
Additionally, data ownership rules are taken into consideration when data is
71
transferred from C++ to QML. See \l {Data Ownership} for more details.
72
73
74
\section1 Exposing Properties
75
76
A \e property can be specified for any QObject-derived class using the
77
Q_PROPERTY() macro. A property is a class data member with an associated read
78
function and optional write function.
79
80
All properties of a QObject-derived or Q_GADGET class are accessible from QML.
81
82
For example, below is a \c Message class with an \c author property. As
83
specified by the Q_PROPERTY macro call, this property is readable through
84
the \c author() method, and writable through the \c setAuthor() method:
85
86
\note Do not use \e typedef or \e using for Q_PROPERTY types as these
87
will confuse moc. This may make certain type comparisons fail.
88
89
Instead of:
90
91
\badcode
92
using FooEnum = Foo::Enum;
93
94
class Bar : public QObject
95
{
96
Q_OBJECT
97
Q_PROPERTY(FooEnum enum READ enum WRITE setEnum NOTIFY enumChanged)
98
};
99
\endcode
100
101
Refer to the type directly:
102
103
\code
104
class Bar : public QObject
105
{
106
Q_OBJECT
107
Q_PROPERTY(Foo::Enum enum READ enum WRITE setEnum NOTIFY enumChanged)
108
};
109
\endcode
110
111
In order to make \c Message available you need to use \l{QML_ELEMENT} in C++
112
and \l{qt_add_qml_module} in CMake.
113
114
\code
115
class Message : public QObject
116
{
117
Q_OBJECT
118
QML_ELEMENT
119
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
120
public:
121
void setAuthor(const QString &a)
122
{
123
if (a != m_author) {
124
m_author = a;
125
emit authorChanged();
126
}
127
}
128
129
QString author() const
130
{
131
return m_author;
132
}
133
134
signals:
135
void authorChanged();
136
137
private:
138
QString m_author;
139
};
140
\endcode
141
142
An instance of \c Message can be passed as required property to a file called
143
\c MyItem.qml to make it available:
144
145
\code
146
int main(int argc, char *argv[]) {
147
QGuiApplication app(argc, argv);
148
149
QQuickView view;
150
Message msg;
151
view.setInitialProperties({{"msg", &msg}});
152
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
153
view.show();
154
155
return app.exec();
156
}
157
\endcode
158
159
Then, the \c author property could be read from \c MyItem.qml:
160
161
\qml
162
// MyItem.qml
163
import QtQuick
164
165
Text {
166
required property Message msg
167
168
width: 100; height: 100
169
text: msg.author // invokes Message::author() to get this value
170
171
Component.onCompleted: {
172
msg.author = "Jonah" // invokes Message::setAuthor()
173
}
174
}
175
\endqml
176
177
For maximum interoperability with QML, \b {any property that is writable should
178
have an associated NOTIFY signal} that is emitted whenever the property value
179
has changed. This allows the property to be used with \l{Property
180
Binding}{property binding}, which is an essential feature of QML that enforces
181
relationships between properties by automatically updating a property whenever
182
any of its dependencies change in value.
183
184
In 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
186
whenever the signal is emitted — as it is when the author changes
187
in Message::setAuthor() — this notifies the QML engine that any
188
bindings involving the \c author property must be updated, and in turn, the
189
engine will update the \c text property by calling \c Message::author() again.
190
191
If the \c author property was writable but did not have an associated NOTIFY
192
signal, the \c text value would be initialized with the initial value returned
193
by \c Message::author() but would not be updated with any later changes to this
194
property. In addition, any attempts to bind to the property from QML will
195
produce a runtime warning from the engine.
196
197
\note It is recommended that the NOTIFY signal be named \e <property>Changed
198
where \c <property> is the name of the property. The associated property
199
change 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
201
it is recommended that the signal name follows this convention to avoid any
202
confusion.
203
204
205
\section3 Notes on Use of Notify Signals
206
207
To prevent loops or excessive evaluation, developers should ensure that the
208
property change signal is only emitted when the property value has actually
209
changed. Also, if a property or group of properties is infrequently used, it
210
is permitted to use the same NOTIFY signal for several properties. This should
211
be done with care to ensure that performance doesn't suffer.
212
213
The presence of a NOTIFY signal does incur a small overhead. There are cases
214
where a property's value is set at object construction time, and does not
215
subsequently 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
217
only freed when the object is deleted. In these cases, the CONSTANT
218
attribute may be added to the property declaration instead of a NOTIFY
219
signal.
220
221
The CONSTANT attribute should only be used for properties whose value is set,
222
and finalized, only in the class constructor. All other properties that want
223
to be used in bindings should have a NOTIFY signal instead.
224
225
226
\section2 Properties with Object Types
227
228
Object-type properties are accessible from QML providing that the object type
229
has been appropriately \l{Registering C++ types with the QML type
230
system}{registered} with the QML type system.
231
232
For example, the \c Message type might have a \c body property of type
233
\c MessageBody*:
234
235
\code
236
class Message : public QObject
237
{
238
Q_OBJECT
239
Q_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged)
240
public:
241
MessageBody* body() const;
242
void setBody(MessageBody* body);
243
};
244
245
class MessageBody : public QObject
246
{
247
Q_OBJECT
248
Q_PROPERTY(QString text READ text WRITE text NOTIFY textChanged)
249
// ...
250
}
251
\endcode
252
253
Suppose the \c Message type was \l{Registering C++ types with the QML type
254
system}{registered} with the QML type system, allowing it to be used as an
255
object type from QML code:
256
257
\qml
258
Message {
259
// ...
260
}
261
\endqml
262
263
If the \c MessageBody type was also registered with the type system, it would be
264
possible to assign \c MessageBody to the \c body property of a \c Message, all
265
from within QML code:
266
267
\qml
268
Message {
269
body: MessageBody {
270
text: "Hello, world!"
271
}
272
}
273
\endqml
274
275
276
\section2 Properties with Object-List Types
277
278
Properties containing lists of QObject-derived types can also be exposed to
279
QML. For this purpose, however, one should use QQmlListProperty rather than
280
QList<T> as the property type. This is because QList is not a QObject-derived
281
type, and so cannot provide the necessary QML property characteristics
282
through the Qt meta object system, such as signal notifications when a list
283
is modified.
284
285
For example, the \c MessageBoard class below has a \c messages property of
286
type QQmlListProperty that stores a list of \c Message instances:
287
288
\code
289
class MessageBoard : public QObject
290
{
291
Q_OBJECT
292
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
293
public:
294
QQmlListProperty<Message> messages();
295
296
private:
297
static void append_message(QQmlListProperty<Message> *list, Message *msg);
298
299
QList<Message *> m_messages;
300
};
301
\endcode
302
303
The MessageBoard::messages() function simply creates and returns a
304
QQmlListProperty from its QList<T> \c m_messages member, passing the
305
appropriate list modification functions as required by the QQmlListProperty
306
constructor:
307
308
\code
309
QQmlListProperty<Message> MessageBoard::messages()
310
{
311
return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message);
312
}
313
314
void MessageBoard::append_message(QQmlListProperty<Message> *list, Message *msg)
315
{
316
MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object);
317
if (msg)
318
msgBoard->m_messages.append(msg);
319
}
320
\endcode
321
322
Note 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.
325
326
327
\section2 Grouped Properties
328
\keyword Integrating QML and C++ - Grouped Properties
329
330
Any 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
332
properties that describe a set of attributes for a type.
333
334
For example, suppose the \c Message::author property was of type
335
\c MessageAuthor rather than a simple string, with sub-properties
336
of \c name and \c email:
337
338
\code
339
class MessageAuthor : public QObject
340
{
341
Q_PROPERTY(QString name READ name WRITE setName)
342
Q_PROPERTY(QString email READ email WRITE setEmail)
343
public:
344
...
345
};
346
347
class Message : public QObject
348
{
349
Q_OBJECT
350
Q_PROPERTY(MessageAuthor* author READ author)
351
public:
352
Message(QObject *parent)
353
: QObject(parent), m_author(new MessageAuthor(this))
354
{
355
}
356
MessageAuthor *author() const {
357
return m_author;
358
}
359
private:
360
MessageAuthor *m_author;
361
};
362
\endcode
363
364
The \c author property could be written to using the
365
\l{qtqml-syntax-objectattributes.html#grouped-properties}{grouped property
366
syntax}
367
in QML, like this:
368
369
\qml
370
Message {
371
author.name: "Alexandra"
372
author.email: "alexandra@mail.com"
373
}
374
\endqml
375
376
A type that is exposed as a grouped property differs from an \l{Properties with
377
Object Types}{object-type property} in that the grouped property is read-only,
378
and is initialized to a valid value by the parent object at construction. The
379
grouped property's sub-properties may be modified from QML but the grouped
380
property object itself will never change, whereas an object-type property may be
381
assigned a new object value from QML at any time. Thus, the lifetime of a
382
grouped property object is controlled strictly by the C++ parent
383
implementation, whereas an object-type property can be freely created and
384
destroyed through QML code.
385
386
387
\section1 Exposing Methods (Including Qt Slots)
388
389
Any method of a QObject-derived type is accessible from QML code if it is:
390
391
\list
392
\li A public method flagged with the Q_INVOKABLE() macro
393
\li A method that is a public Qt \l{Signals & Slots}{slot}
394
\endlist
395
396
For example, the \c MessageBoard class below has a \c postMessage() method that
397
has been flagged with the Q_INVOKABLE macro, as well as a \c refresh() method
398
that is a public slot:
399
400
\code
401
class MessageBoard : public QObject
402
{
403
Q_OBJECT
404
QML_ELEMENT
405
406
public:
407
Q_INVOKABLE bool postMessage(const QString &msg) {
408
qDebug() << "Called the C++ method with" << msg;
409
return true;
410
}
411
412
public slots:
413
void refresh() {
414
qDebug() << "Called the C++ slot";
415
}
416
};
417
\endcode
418
419
If an instance of \c MessageBoard was set as the required property for a file \c
420
MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
421
examples below:
422
423
\table
424
\row
425
\li C++
426
\li
427
\code
428
int main(int argc, char *argv[]) {
429
QGuiApplication app(argc, argv);
430
431
MessageBoard msgBoard;
432
QQuickView view;
433
view.setInitialProperties({{"msgBoard", &msgBoard}});
434
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
435
view.show();
436
437
return app.exec();
438
}
439
\endcode
440
\row
441
\li QML
442
\li
443
\qml
444
// MyItem.qml
445
import QtQuick 2.0
446
447
Item {
448
required property MessageBoard msgBoard
449
450
width: 100; height: 100
451
452
MouseArea {
453
anchors.fill: parent
454
onClicked: {
455
var result = msgBoard.postMessage("Hello from QML")
456
console.log("Result of postMessage():", result)
457
msgBoard.refresh();
458
}
459
}
460
}
461
\endqml
462
\endtable
463
464
If a C++ method has a parameter with a \c QObject* type, the parameter value
465
can be passed from QML using an object \c id or a JavaScript \l var value
466
that references the object.
467
468
QML supports the calling of overloaded C++ functions. If there are multiple C++
469
functions with the same name but different arguments, the correct function will
470
be called according to the number and the types of arguments that are provided.
471
472
Values returned from C++ methods are converted to JavaScript values when
473
accessed from JavaScript expressions in QML.
474
475
\section2 C++ methods and the 'this' object
476
477
You may want to retrieve a C++ method from one object and call it on a different
478
object. Consider the following example, within a QML module called \c{Example}:
479
480
\table
481
\row
482
\li C++
483
\li
484
\code
485
class Invokable : public QObject
486
{
487
Q_OBJECT
488
QML_ELEMENT
489
public:
490
Invokable(QObject *parent = nullptr) : QObject(parent) {}
491
492
Q_INVOKABLE void invoke() { qDebug() << "invoked on " << objectName(); }
493
};
494
\endcode
495
\row
496
\li QML
497
\li
498
\qml
499
import QtQml
500
import Example
501
502
Invokable {
503
objectName: "parent"
504
property Invokable child: Invokable {}
505
Component.onCompleted: child.invoke.call(this)
506
}
507
\endqml
508
\endtable
509
510
If 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.
512
Historically, the 'this' object of C++-based methods is inseparably bound to
513
the method. Changing this behavior for existing code would cause subtle errors
514
since the 'this' object is implicit in many places. Since Qt 6.5 you can
515
explicitly 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:
517
518
\qml
519
pragma NativeMethodBehavior: AcceptThisObject
520
\endqml
521
522
With this line added, the example above will work as expected.
523
524
\section2 Overriding toString()
525
526
If you provide a Q_INVOKABLE method called \e{toString} (with no arguments), that
527
method will be used to convert the object to a string in place of JavaScript's
528
native \e{toString} implementation.
529
530
\section1 Exposing Signals
531
532
Any public \l{Signals & Slots}{signal} of a QObject-derived type is accessible
533
from QML code.
534
535
The QML engine automatically creates a \l{Signal and Handler Event
536
System}{signal handler} for any signal of a QObject-derived type that is used
537
from QML. Signal handlers are always named \e on<Signal> where \c <Signal> is
538
the name of the signal, with the first letter capitalized. All parameters passed
539
by the signal are available in the signal handler through the parameter names.
540
541
For example, suppose the \c MessageBoard class has a \c newMessagePosted()
542
signal with a single parameter, \c subject:
543
544
\code
545
class MessageBoard : public QObject
546
{
547
Q_OBJECT
548
public:
549
// ...
550
signals:
551
void newMessagePosted(const QString &subject);
552
};
553
\endcode
554
555
If the \c MessageBoard type was \l{Registering C++ types with the QML type
556
system}{registered} with the QML type system, then a \c MessageBoard object
557
declared in QML could receive the \c newMessagePosted() signal using a signal
558
handler named \c onNewMessagePosted, and examine the \c subject parameter
559
value:
560
561
\qml
562
MessageBoard {
563
onNewMessagePosted: (subject)=> console.log("New message received:", subject)
564
}
565
\endqml
566
567
As with property values and method parameters, a signal parameter must have a
568
type that is supported by the QML engine; see
569
\l {Data Type Conversion Between QML and C++}. (Using an
570
unregistered type will not generate an error, but the parameter value will
571
not be accessible from the handler.)
572
573
Classes may have multiple signals with the same name, but only the final
574
signal is accessible as a QML signal. Note that signals with the same name
575
but different parameters cannot be distinguished from one another.
576
577
578
*/
qtdeclarative
src
qml
doc
src
cppintegration
exposecppattributes.qdoc
Generated on
for Qt by
1.14.0