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 \l[Cpp]{QtQuick} so that your
45
QML-exposed C++ types can use \l QColor as method arguments and return values.
46
\l[Cpp]{QtQuick} exposes \l QColor as a \l {QML Value Types}{value type} \e color.
47
Such dependencies may be automatically inferred at run time, but you should not
48
rely 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 a read-only property that
216
holds a sub-object, typically accessed through
217
\l{#Grouped Properties}{grouped property syntax}, where the sub-object is
218
allocated once, and only freed when the owner is deleted. In these cases,
219
the CONSTANT attribute may be added to the property declaration instead of a
220
NOTIFY signal.
221
222
The CONSTANT attribute should only be used for properties whose value is set,
223
and finalized, only in the class constructor. All other properties that want
224
to be used in bindings should have a NOTIFY signal instead.
225
226
227
\section2 Properties with Object Types
228
229
Object-type properties are accessible from QML providing that the object type
230
has been appropriately \l{Registering C++ Types with the QML Type
231
System}{registered} with the QML type system.
232
233
For example, the \c Message type might have a \c body property of type
234
\c MessageBody*:
235
236
\code
237
class Message : public QObject
238
{
239
Q_OBJECT
240
Q_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged)
241
public:
242
MessageBody* body() const;
243
void setBody(MessageBody* body);
244
};
245
246
class MessageBody : public QObject
247
{
248
Q_OBJECT
249
Q_PROPERTY(QString text READ text WRITE text NOTIFY textChanged)
250
// ...
251
}
252
\endcode
253
254
Suppose the \c Message type was \l{Registering C++ Types with the QML Type
255
System}{registered} with the QML type system, allowing it to be used as an
256
object type from QML code:
257
258
\qml
259
Message {
260
// ...
261
}
262
\endqml
263
264
If the \c MessageBody type was also registered with the type system, it would be
265
possible to assign \c MessageBody to the \c body property of a \c Message, all
266
from within QML code:
267
268
\qml
269
Message {
270
body: MessageBody {
271
text: "Hello, world!"
272
}
273
}
274
\endqml
275
276
277
\section2 Properties with Object-List Types
278
279
Properties containing lists of QObject-derived types can also be exposed to
280
QML. For this purpose, however, one should use QQmlListProperty rather than
281
QList<T> as the property type. This is because QList is not a QObject-derived
282
type, and so cannot provide the necessary QML property characteristics
283
through the Qt meta object system, such as signal notifications when a list
284
is modified.
285
286
For example, the \c MessageBoard class below has a \c messages property of
287
type QQmlListProperty that stores a list of \c Message instances:
288
289
\code
290
class MessageBoard : public QObject
291
{
292
Q_OBJECT
293
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
294
public:
295
QQmlListProperty<Message> messages();
296
297
private:
298
static void append_message(QQmlListProperty<Message> *list, Message *msg);
299
300
QList<Message *> m_messages;
301
};
302
\endcode
303
304
The MessageBoard::messages() function simply creates and returns a
305
QQmlListProperty from its QList<T> \c m_messages member, passing the
306
appropriate list modification functions as required by the QQmlListProperty
307
constructor:
308
309
\code
310
QQmlListProperty<Message> MessageBoard::messages()
311
{
312
return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message);
313
}
314
315
void MessageBoard::append_message(QQmlListProperty<Message> *list, Message *msg)
316
{
317
MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object);
318
if (msg)
319
msgBoard->m_messages.append(msg);
320
}
321
\endcode
322
323
Note that the template class type for the QQmlListProperty — in this case,
324
\c Message — must be \l{Registering C++ Types with the QML Type System}
325
{registered} with the QML type system.
326
327
328
\section2 Grouped Properties
329
\keyword Integrating QML and C++ - Grouped Properties
330
331
Any property whose type has sub-properties of its own can be manipulated using
332
the \l{QML Object Attributes#Grouped Properties}{grouped property syntax}, no
333
matter whether that type is a value type such as \c font or an object type.
334
Grouped properties are useful to expose a group of related properties that
335
describe a set of attributes for a type.
336
337
For example, suppose the \c Message::author property was of type
338
\c MessageAuthor rather than a simple string, with sub-properties
339
of \c name and \c email:
340
341
\code
342
class MessageAuthor : public QObject
343
{
344
Q_PROPERTY(QString name READ name WRITE setName)
345
Q_PROPERTY(QString email READ email WRITE setEmail)
346
public:
347
...
348
};
349
350
class Message : public QObject
351
{
352
Q_OBJECT
353
Q_PROPERTY(MessageAuthor* author READ author)
354
public:
355
Message(QObject *parent)
356
: QObject(parent), m_author(new MessageAuthor(this))
357
{
358
}
359
MessageAuthor *author() const {
360
return m_author;
361
}
362
private:
363
MessageAuthor *m_author;
364
};
365
\endcode
366
367
The \c author property could be written to using the
368
\l{QML Object Attributes#Grouped Properties}{grouped property syntax} in QML,
369
like this:
370
371
\qml
372
Message {
373
author.name: "Alexandra"
374
author.email: "alexandra@mail.com"
375
}
376
\endqml
377
378
Since \c author is an \l{Properties with Object Types}{object-type property},
379
the grouped assignments do not create the \c MessageAuthor object. They are
380
written to whatever object \c Message::author() returns. This has a few
381
consequences:
382
383
\list
384
\li The sub-property names are resolved against the \e declared type of the
385
property, here \c MessageAuthor, not against the type of the object that
386
happens to be stored in it at run time. Different instantiations of
387
\c Message could produce \c author objects of different types. The only
388
thing we can rely on when creating the QML component is the declared type.
389
\li The object has to exist when the grouped assignments are applied.
390
Otherwise the engine throws an error along the lines of
391
\c {Cannot set properties on author as it is null}. Creating the object in
392
the owner's constructor, as above, is the simplest way to guarantee this,
393
but a getter that creates the object on first access works just as well.
394
\li The lifetime of the object is whatever the C++ implementation makes it.
395
Grouped property syntax neither creates nor destroys objects.
396
\endlist
397
398
Declaring \c author read-only, as in the example above, additionally prevents
399
QML code from replacing the \c MessageAuthor object. If \c author had a
400
\c WRITE accessor, you could equally well assign a new object to it:
401
402
\qml
403
Message {
404
author: MessageAuthor {
405
name: "Alexandra"
406
email: "alexandra@mail.com"
407
}
408
}
409
\endqml
410
411
You cannot combine the two forms for the same property in the same
412
object definition. Assigning an object to \c author and also writing
413
\c author.name in the same \c Message produces an error. You can subvert that
414
by having the grouped property in a different scope. However, doing so produces
415
confusing results because now you have two \c MessageAuthor objects, the one
416
created by the constructor and the one assigned explicitly. Only binding
417
evaluation order determines which one the grouped property applies to.
418
419
This means that the good practice is:
420
421
\list
422
\li Keep objects used as grouped properties read-only.
423
\li Avoid grouped property syntax if you also manipulate the base property of
424
the group itself.
425
\endlist
426
427
For a \l {QML Value Types}{value type} property such as \c font, grouped
428
assignments require the property to be writable, since the engine reads the
429
value, modifies it, and writes it back. The potential confusion is still a
430
problem, though. If you re-assign the whole \c font in place and then manipulate
431
the \c font.bold property in a different place, binding evaluation order
432
determines which one is done first, and what value of \c bold will result from
433
it.
434
435
436
\section1 Exposing Methods (Including Qt Slots)
437
438
Any method of a QObject-derived type is accessible from QML code if it is:
439
440
\list
441
\li A public method flagged with the Q_INVOKABLE() macro
442
\li A method that is a public Qt \l{Signals & Slots}{slot}
443
\endlist
444
445
For example, the \c MessageBoard class below has a \c postMessage() method that
446
has been flagged with the Q_INVOKABLE macro, as well as a \c refresh() method
447
that is a public slot:
448
449
\code
450
class MessageBoard : public QObject
451
{
452
Q_OBJECT
453
QML_ELEMENT
454
455
public:
456
Q_INVOKABLE bool postMessage(const QString &msg) {
457
qDebug() << "Called the C++ method with" << msg;
458
return true;
459
}
460
461
public slots:
462
void refresh() {
463
qDebug() << "Called the C++ slot";
464
}
465
};
466
\endcode
467
468
If an instance of \c MessageBoard was set as the required property for a file \c
469
MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
470
examples below:
471
472
\table
473
\row
474
\li C++
475
\li
476
\code
477
int main(int argc, char *argv[]) {
478
QGuiApplication app(argc, argv);
479
480
MessageBoard msgBoard;
481
QQuickView view;
482
view.setInitialProperties({{"msgBoard", &msgBoard}});
483
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
484
view.show();
485
486
return app.exec();
487
}
488
\endcode
489
\row
490
\li QML
491
\li
492
\qml
493
// MyItem.qml
494
import QtQuick 2.0
495
496
Item {
497
required property MessageBoard msgBoard
498
499
width: 100; height: 100
500
501
MouseArea {
502
anchors.fill: parent
503
onClicked: {
504
var result = msgBoard.postMessage("Hello from QML")
505
console.log("Result of postMessage():", result)
506
msgBoard.refresh();
507
}
508
}
509
}
510
\endqml
511
\endtable
512
513
If a C++ method has a parameter with a \c QObject* type, the parameter value
514
can be passed from QML using an object \c id or a JavaScript \l var value
515
that references the object.
516
517
QML supports the calling of overloaded C++ functions. If there are multiple C++
518
functions with the same name but different arguments, the correct function will
519
be called according to the number and the types of arguments that are provided.
520
521
Values returned from C++ methods are converted to JavaScript values when
522
accessed from JavaScript expressions in QML.
523
524
\section2 C++ methods and the 'this' object
525
526
You may want to retrieve a C++ method from one object and call it on a different
527
object. Consider the following example, within a QML module called \c{Example}:
528
529
\table
530
\row
531
\li C++
532
\li
533
\code
534
class Invokable : public QObject
535
{
536
Q_OBJECT
537
QML_ELEMENT
538
public:
539
Invokable(QObject *parent = nullptr) : QObject(parent) {}
540
541
Q_INVOKABLE void invoke() { qDebug() << "invoked on " << objectName(); }
542
};
543
\endcode
544
\row
545
\li QML
546
\li
547
\qml
548
import QtQml
549
import Example
550
551
Invokable {
552
objectName: "parent"
553
property Invokable child: Invokable {}
554
Component.onCompleted: child.invoke.call(this)
555
}
556
\endqml
557
\endtable
558
559
If you load the QML code from a suitable main.cpp, it should print
560
"invoked on parent". However, due to a long standing bug, it doesn't.
561
Historically, the 'this' object of C++-based methods is inseparably bound to
562
the method. Changing this behavior for existing code would cause subtle errors
563
since the 'this' object is implicit in many places. Since Qt 6.5 you can
564
explicitly opt into the correct behavior and allow C++ methods to accept a
565
'this' object. To do so, add the following pragma to your QML documents:
566
567
\qml
568
pragma NativeMethodBehavior: AcceptThisObject
569
\endqml
570
571
With this line added, the example above will work as expected.
572
573
\section2 Overriding toString()
574
575
If you provide a Q_INVOKABLE method called \e{toString} (with no arguments), that
576
method will be used to convert the object to a string in place of JavaScript's
577
native \e{toString} implementation.
578
579
\section1 Exposing Signals
580
581
Any public \l{Signals & Slots}{signal} of a QObject-derived type is accessible
582
from QML code.
583
584
The QML engine automatically creates a \l{Signal and Handler Event
585
System}{signal handler} for any signal of a QObject-derived type that is used
586
from QML. Signal handlers are always named \e on<Signal> where \c <Signal> is
587
the name of the signal, with the first letter capitalized. All parameters passed
588
by the signal are available in the signal handler through the parameter names.
589
590
For example, suppose the \c MessageBoard class has a \c newMessagePosted()
591
signal with a single parameter, \c subject:
592
593
\code
594
class MessageBoard : public QObject
595
{
596
Q_OBJECT
597
public:
598
// ...
599
signals:
600
void newMessagePosted(const QString &subject);
601
};
602
\endcode
603
604
If the \c MessageBoard type was \l{Registering C++ Types with the QML Type
605
System}{registered} with the QML type system, then a \c MessageBoard object
606
declared in QML could receive the \c newMessagePosted() signal using a signal
607
handler named \c onNewMessagePosted, and examine the \c subject parameter
608
value:
609
610
\qml
611
MessageBoard {
612
onNewMessagePosted: (subject)=> console.log("New message received:", subject)
613
}
614
\endqml
615
616
As with property values and method parameters, a signal parameter must have a
617
type that is supported by the QML engine; see
618
\l {Data Type Conversion Between QML and C++}. (Using an
619
unregistered type will not generate an error, but the parameter value will
620
not be accessible from the handler.)
621
622
Classes may have multiple signals with the same name, but only the final
623
signal is accessible as a QML signal. Note that signals with the same name
624
but different parameters cannot be distinguished from one another.
625
626
\sa {qqmlintegration.h}{QML Type Registration Macros}, {Defining QML Types from C++}
627
*/
qtdeclarative
src
qml
doc
src
cppintegration
exposecppattributes.qdoc
Generated on
for Qt by
1.16.1