Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
data.qdoc
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3/*!
4\page qtqml-cppintegration-data.html
5\title Data Type Conversion Between QML and C++
6\brief Description of how data types are exchanged between QML and C++
7
8When data values are exchanged between QML and C++, they are converted by the
9QML engine to have the correct data types as appropriate for use in QML or
10C++. This requires the exchanged data to be of a type that is recognizable by
11the engine.
12
13The QML engine provides built-in support for a large number of Qt C++ data
14types. Additionally, custom C++ types may be registered with the QML type
15system to make them available to the engine.
16
17For more information about C++ and the different QML integration methods,
18see the
19\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
20
21This page discusses the data types supported by the QML engine and how
22they are converted between QML and C++.
23
24
25\section1 Data Ownership
26
27When data is transferred from C++ to QML, the ownership of the data always
28remains with C++. The exception to this rule is when a QObject is returned from
29an explicit C++ method call: in this case, the QML engine assumes ownership of
30the object, unless the ownership of the object has explicitly been set to
31remain with C++ by invoking QQmlEngine::setObjectOwnership() with
32QQmlEngine::CppOwnership specified.
33
34Additionally, the QML engine respects the normal QObject parent ownership
35semantics of Qt C++ objects, and will never delete a QObject instance which
36has a parent.
37
38
39\section1 Basic Qt Data Types
40
41By default, QML recognizes the following Qt data types, which are
42automatically converted to a corresponding \l {QML Value Types}{QML value type}
43when passed from C++ to QML and vice-versa:
44
45\table
46 \row
47 \li Qt Type
48 \li QML Value Type
49 \row
50 \li bool
51 \li \l bool
52 \row
53 \li unsigned int, int
54 \li \l int
55 \row
56 \li double
57 \li \l double
58 \row
59 \li float, qreal
60 \li \l real
61 \row
62 \li QString
63 \li \l string
64 \row
65 \li QUrl
66 \li \l url
67 \row
68 \li QColor
69 \li \l color
70 \row
71 \li QFont
72 \li \l font
73 \row
74 \li QDateTime
75 \li \l date
76 \row
77 \li QPoint, QPointF
78 \li \l point
79 \row
80 \li QSize, QSizeF
81 \li \l size
82 \row
83 \li QRect, QRectF
84 \li \l rect
85 \row
86 \li QMatrix4x4
87 \li \l matrix4x4
88 \row
89 \li QQuaternion
90 \li \l quaternion
91 \row
92 \li QVector2D, QVector3D, QVector4D
93 \li \l vector2d, \l vector3d, \l vector4d
94 \row
95 \li Enums declared with Q_ENUM()
96 \li \l enumeration
97\endtable
98
99\note Classes provided by the \l {Qt GUI} module, such as QColor, QFont,
100QQuaternion and QMatrix4x4, are only available from QML when the \l {Qt Quick}
101module is included.
102
103As a convenience, many of these types can be specified in QML by string values,
104or by a related method provided by the \l {QtQml::Qt} object. For example, the \l
105{Image::sourceSize} property is of type \l size (which automatically translates
106to the QSize type) and can be specified by a string value formatted as
107"width\c{x}height", or by the Qt.size() function:
108
109\qml
110Item {
111 Image { sourceSize: "100x200" }
112 Image { sourceSize: Qt.size(100, 200) }
113}
114\endqml
115
116See documentation for each individual type under \l {QML Value Types} for more
117information.
118
119
120\section1 QObject-derived Types
121
122Any QObject-derived class may be used as a type for the exchange of data between
123QML and C++, providing the class has been registered with the QML type system.
124
125The engine allows the registration of both instantiable and non-instantiable
126types. Once a class is registered as a QML type, it can be used as a data type
127for exchanging data between QML and C++. See
128\l{qtqml-cppintegration-definetypes.html#registering-c++-types-with-the-qml-type-system}{Registering C++ types with the QML type system} for further details on type registration.
129
130
131\section1 Conversion Between Qt and JavaScript Types
132
133The QML engine has built-in support for converting a number of Qt types to
134related JavaScript types, and vice-versa, when transferring data between QML
135and C++. This makes it possible to use these types and receive them in C++ or
136JavaScript without needing to implement custom types that provide access to
137the data values and their attributes.
138
139(Note that the JavaScript environment in QML modifies native JavaScript object
140prototypes, including those of \c String, \c Date and \c Number, to provide
141additional features. See the \l {qtqml-javascript-hostenvironment.html}
142{JavaScript Host Environment} for further details.)
143
144
145\section2 QVariantList and QVariantMap to JavaScript Array and Object
146
147The QML engine provides automatic type conversion between QVariantList and
148JavaScript arrays, and between QVariantMap and JavaScript objects.
149
150For example, the function defined in QML below expects two arguments, an
151array and an object, and prints their contents using the standard JavaScript
152syntax for array and object item access. The C++ code below calls this
153function, passing a QVariantList and a QVariantMap, which are automatically
154converted to JavaScript array and object values, repectively:
155
156\table
157\row
158\li QML
159\li \snippet qml/qtbinding/variantlistmap/MyItem.qml 0
160\row
161\li C++
162\li \snippet qml/qtbinding/variantlistmap/main.cpp 0
163\endtable
164
165This produces output like:
166
167\code
168Array item: 10
169Array item: #00ff00
170Array item: bottles
171Object item: language = QML
172Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)
173\endcode
174
175Similarly, if a C++ type uses a QVariantList or QVariantMap type for a property
176type or method parameter, the value can be created as a JavaScript array or
177object in QML, and is automatically converted to a QVariantList or QVariantMap
178when it is passed to C++.
179
180Mind that QVariantList and QVariantMap properties of C++ types are stored as
181values and cannot be changed in place by QML code. You can only replace the
182whole map or list, but not manipulate its contents. The following code does
183not work if the property \c l is a QVariantList:
184
185\code
186MyListExposingItem {
187 l: [1, 2, 3]
188 Component.onCompleted: l[0] = 10
189}
190\endcode
191
192The following code does work:
193\code
194MyListExposingItem {
195 l: [1, 2, 3]
196 Component.onCompleted: l = [10, 2, 3]
197}
198\endcode
199
200\section2 QDateTime to JavaScript Date
201
202The QML engine provides automatic type conversion between QDateTime values and
203JavaScript \c Date objects.
204
205For example, the function defined in QML below expects a JavaScript
206\c Date object, and also returns a new \c Date object with the current date and
207time. The C++ code below calls this function, passing a QDateTime value
208that is automatically converted by the engine into a \c Date object when it is
209passed to the \c readDate() function. In turn, the readDate() function returns
210a \c Date object that is automatically converted into a QDateTime value when it
211is received in C++:
212
213\table
214\row
215\li QML
216\li
217\qml
218// MyItem.qml
219Item {
220 function readDate(dt) {
221 console.log("The given date is:", dt.toUTCString());
222 return new Date();
223 }
224}
225\endqml
226\row
227\li C++
228\li
229\code
230// C++
231QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
232
233QDateTime dateTime = QDateTime::currentDateTime();
234QDateTime retValue;
235
236QMetaObject::invokeMethod(view.rootObject(), "readDate",
237 Q_RETURN_ARG(QVariant, retValue),
238 Q_ARG(QVariant, QVariant::fromValue(dateTime)));
239
240qDebug() << "Value returned from readDate():" << retValue;
241\endcode
242
243\endtable
244
245Similarly, if a C++ type uses a QDateTime for a property type or method
246parameter, the value can be created as a JavaScript \c Date object in QML, and
247is automatically converted to a QDateTime value when it is passed to C++.
248
249\note Watch out for the difference in month numbering: JavaScript numbers
250January as 0 through 11 for December, off by one from Qt's numbering
251of January as 1 through 12 for December.
252
253\note When using a string in JavaScript as the value of a \c Date object,
254note that a string with no time fields (so a simple date) is
255interpreted as the UTC start of the relevant day, in contrast
256to \c{new Date(y, m, d)} which uses the local time start of the day.
257Most other ways of constructing a \c Date object in JavaScript produce
258a local time, unless methods with UTC in their names are used. If your
259program is run in a zone behind UTC (nominally west of The Prime
260Meridian), use of a date-only string will lead to a \c Date object
261whose \c getDate() is one less than the day-number in your string; it
262will typically have a large value for \c getHours(). The UTC variants
263of these methods, \c getUTCDate() and \c getUTCHours(), will give the
264results you expect for such a \c Date objects. See also the next
265section.
266
267\section2 QDate and JavaScript Date
268
269The QML engine converts automatically between \l QDate and the
270JavaScript \c Date type by representing the date by the UTC start of
271its day. A date is mapped back to QDate via QDateTime, selecting
272its \l {QDateTime::}{date()} method, using the local time form of the
273date unless the UTC form of it coincides with the start of the next
274day, in which case the UTC form is used.
275
276This slighly eccentric arrangement is a work-around for the fact that
277JavaScript's construction of a \c Date object from a date-only string
278uses the UTC start of the day, but \c{new Date(y, m, d)} uses the
279local time start of the indicated date, as discussed in a note at the
280end of the previous section.
281
282As a result, where a QDate property or parameter is exposed to QML,
283care should be taken in reading its value: the \c
284Date.getUTCFullYear(), \c Date.getUTCMonth() and \c Date.getUTCDate()
285methods are more likely to deliver the results users expect than the
286corresponding methods without UTC in their names.
287
288It is thus commonly more robust to use a \l QDateTime property. This
289makes it possible to take control, on the QDateTime side, of whether
290the date (and time) is specified in terms of UTC or local time; as
291long as the JavaScript code is written to work with the same standard,
292it should be possible to avoid trouble.
293
294//! Target adds an anchor, so renaming the section won't break incoming links.
295\target QTime to JavaScript Date
296\section2 QTime and JavaScript Date
297
298The QML engine provides automatic type conversion from QTime values to
299JavaScript \c Date objects. As QTime values do not contain a date component,
300one is created for the conversion only. Thus, you should not rely on the date
301component of the resulting Date object.
302
303Under the hood, conversion from a JavaScript \c Date object to QTime
304is done by converting to a QDateTime object (using local time) and
305calling its \l {QDateTime::}{time()} method.
306
307\section2 Sequence Type to JavaScript Array
308
309Certain C++ sequence types are supported transparently in QML to behave like
310JavaScript \c Array types.
311
312In particular, QML currently supports:
313\list
314 \li \c {QList<int>}
315 \li \c {QList<qreal>}
316 \li \c {QList<bool>}
317 \li \c {QList<QString>} and \c{QStringList}
318 \li \c {QVector<QString>}
319 \li \c {std::vector<QString>}
320 \li \c {QList<QUrl>}
321 \li \c {QVector<QUrl>}
322 \li \c {std::vector<QUrl>}
323 \li \c {QVector<int>}
324 \li \c {QVector<qreal>}
325 \li \c {QVector<bool>}
326 \li \c {std::vector<int>}
327 \li \c {std::vector<qreal>}
328 \li \c {std::vector<bool>}
329\endlist
330
331and all registered QList, QVector, QQueue, QStack, QSet, std::list,
332std::vector that contain a type marked with \l Q_DECLARE_METATYPE.
333
334These sequence types are implemented directly in terms of the underlying C++
335sequence. There are two ways in which such sequences can be exposed to QML:
336as a Q_PROPERTY of the given sequence type; or as the return type of a
337Q_INVOKABLE method. There are some differences in the way these are
338implemented, which are important to note.
339
340If the sequence is exposed as a Q_PROPERTY, accessing any value in the
341sequence by index will cause the sequence data to be read from the QObject's
342property, then a read to occur. Similarly, modifying any value in the
343sequence will cause the sequence data to be read, and then the modification
344will be performed and the modified sequence will be written back to the
345QObject's property.
346
347If the sequence is returned from a Q_INVOKABLE function, access and mutation
348is much cheaper, as no QObject property read or write occurs; instead, the
349C++ sequence data is accessed and modified directly.
350
351In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
352of a std::vector are copied. This copying may be an expensive operation,
353so std::vector should be used judiciously.
354
355You can also create a list-like data structure by constructing a QJSValue using
356QJSEngine::newArray(). Such a JavaScript array does not need any conversion
357when passing it between QML and C++. See \l{QJSValue#Working With Arrays} for
358details on how to manipulate JavaScript arrays from C++.
359
360Other sequence types are not supported transparently, and instead an
361instance of any other sequence type will be passed between QML and C++ as an
362opaque QVariantList.
363
364\b {Important Note:} There are some minor differences between the
365semantics of such sequence Array types and default JavaScript Array types
366which result from the use of a C++ storage type in the implementation. In
367particular, deleting an element from an Array will result in a
368default-constructed value replacing that element, rather than an Undefined
369value. Similarly, setting the length property of the Array to a value larger
370than its current value will result in the Array being padded out to the
371specified length with default-constructed elements rather than Undefined
372elements. Finally, the Qt container classes support signed (rather than
373unsigned) integer indexes; thus, attempting to access any index greater
374than INT_MAX will fail.
375
376The default-constructed values for each sequence type are as follows:
377\table
378\row \li QList<int> \li integer value 0
379\row \li QList<qreal> \li real value 0.0
380\row \li QList<bool> \li boolean value \c {false}
381\row \li QList<QString> and QStringList \li empty QString
382\row \li QVector<QString> \li empty QString
383\row \li std::vector<QString> \li empty QString
384\row \li QList<QUrl> \li empty QUrl
385\row \li QVector<QUrl> \li empty QUrl
386\row \li std::vector<QUrl> \li empty QUrl
387\row \li QVector<int> \li integer value 0
388\row \li QVector<qreal> \li real value 0.0
389\row \li QVector<bool> \li boolean value \c {false}
390\row \li std::vector<int> \li integer value 0
391\row \li std::vector<qreal> \li real value 0.0
392\row \li std::vector<bool> \li boolean value \c {false}
393\endtable
394
395If you wish to remove elements from a sequence rather than simply replace
396them with default constructed values, do not use the indexed delete operator
397("delete sequence[i]") but instead use the \c {splice} function
398("sequence.splice(startIndex, deleteCount)").
399
400\section2 QByteArray to JavaScript ArrayBuffer
401
402The QML engine provides automatic type conversion between QByteArray values and
403JavaScript \c ArrayBuffer objects.
404
405\section2 Value Types
406
407Some value types in Qt such as QPoint are represented in JavaScript as objects
408that have the same properties and functions like in the C++ API. The same
409representation is possible with custom C++ value types. To enable a custom
410value type with the QML engine, the class declaration needs to be annotated
411with \c{Q_GADGET}. Properties that are intended to be visible in the JavaScript
412representation need to be declared with \c Q_PROPERTY. Similarly functions need
413to be marked with \c Q_INVOKABLE. This is the same with QObject based C++ APIs.
414For example, the \c Actor class below is annotated as gadget and has
415properties:
416
417\code
418 class Actor
419 {
420 Q_GADGET
421 Q_PROPERTY(QString name READ name WRITE setName)
422 public:
423 QString name() const { return m_name; }
424 void setName(const QString &name) { m_name = name; }
425
426 private:
427 QString m_name;
428 };
429
430 Q_DECLARE_METATYPE(Actor)
431\endcode
432
433The usual pattern is to use a gadget class as the type of a property, or to
434emit a gadget as a signal argument. In such cases, the gadget instance is
435passed by value between C++ and QML (because it's a value type). If QML code
436changes a property of a gadget property, the entire gadget is re-created and
437passed back to the C++ property setter. In Qt 5, gadget types cannot be
438instantiated by direct declaration in QML. In contrast, a QObject instance can
439be declared; and QObject instances are always passed by pointer from C++ to QML.
440
441\section1 Enumeration Types
442
443To use a custom enumeration as a data type, its class must be registered and
444the enumeration must also be declared with Q_ENUM() to register it with Qt's
445meta object system. For example, the \c Message class below has a \c Status
446enum:
447
448\code
449 class Message : public QObject
450 {
451 Q_OBJECT
452 Q_PROPERTY(Status status READ status NOTIFY statusChanged)
453 public:
454 enum Status {
455 Ready,
456 Loading,
457 Error
458 };
459 Q_ENUM(Status)
460 Status status() const;
461 signals:
462 void statusChanged();
463 };
464\endcode
465
466Providing the \c Message class has been
467\l{qtqml-cppintegration-definetypes.html#registering-c++-types-with-the-qml-type-system}{registered} with the QML type system, its \c Status enum can be used from QML:
468
469\qml
470Message {
471 onStatusChanged: {
472 if (status == Message.Ready)
473 console.log("Message is loaded!")
474 }
475 }
476\endqml
477
478To use an enum as a \l {QFlags}{flags} type in QML, see \l Q_FLAG().
479
480\note The names of enum values must begin with a capital letter in order to
481be accessible from QML.
482
483\code
484...
485enum class Status {
486 Ready,
487 Loading,
488 Error
489}
490Q_ENUM(Status)
491...
492\endcode
493
494Enum classes are registered in QML as scoped and unscoped properties.
495The \c Ready value will be registered at \c Message.Status.Ready and \c Message.Ready .
496
497When using enum classes, there can be multiple enums using the same identifiers.
498The unscoped registration will be overwriten by the last registered enum. For classes
499that contain such name conficts it is possible to disable the unscoped registration by
500annotating your class with a special Q_CLASSINFO macro.
501Use the name \c RegisterEnumClassesUnscoped with the value \c false to prevent scoped
502enums from being merged into the same name space.
503
504\code
505class Message : public QObject
506 {
507 Q_OBJECT
508 Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
509 Q_ENUM(ScopedEnum)
510 Q_ENUM(OtherValue)
511
512 public:
513 enum class ScopedEnum {
514 Value1,
515 Value2,
516 OtherValue
517 };
518 enum class OtherValue {
519 Value1,
520 Value2
521 };
522 };
523\endcode
524
525Enums from related types are usually registered in the scope of the relating
526type. For example any enum from a different type used in a \l{Q_PROPERTY}
527declaration causes all enums from that type to be made available in QML. This
528is usually more of a liability than a feature. In order to prevent it from
529happening, annotate your class with a special \l{Q_CLASSINFO} macro.
530Use the name \c RegisterEnumsFromRelatedTypes with the value \c false to prevent
531enums from related types from being registered in this type.
532
533You should explicitly register the enclosing types of any enums you want to use
534in QML, using \l{QML_ELEMENT} or \l{QML_NAMED_ELEMENT}, rather than rely on
535their enums to be injected into other types.
536
537\code
538class OtherType : public QObject
539{
540 Q_OBJECT
541 QML_ELEMENT
542
543public:
544 enum SomeEnum { A, B, C };
545 Q_ENUM(SomeEnum)
546
547 enum AnotherEnum { D, E, F };
548 Q_ENUM(AnotherEnum)
549};
550
551class Message : public QObject
552{
553 Q_OBJECT
554 QML_ELEMENT
555
556 // This would usually cause all enums from OtherType to be registered
557 // as members of Message ...
558 Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT)
559
560 // ... but this way it doesn't.
561 Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false")
562
563public:
564 OtherType::SomeEnum someEnum() const { return OtherType::B; }
565};
566\endcode
567
568The important difference is the scope for the enums in QML. If an enum from a
569related class is automatically registered, the scope is the type it is
570imported into. In the above case, without the extra \l{Q_CLASSINFO}, you would
571use \c {Message.A}, for example. If C++ type holding the enums is explicitly
572registered, and the registration of enums from related types is suppressed, the
573QML type for the C++ type holding the enums is the scope for all of its enums.
574You would use \c {OtherType.A} instead of \c {Message.A} in QML.
575
576Mind that you can use \l QML_FOREIGN to register a type you cannot modify. You
577can also use \l QML_FOREIGN_NAMESPACE to register the enumerators of a C++ type
578into a QML namespace of any upper-case name, even if the same C++ type is
579also registered as a QML value type.
580
581\section2 Enumeration Types as Signal and Method Parameters
582
583C++ signals and methods with enumeration-type parameters can be used from QML
584provided that the enumeration and the signal or method are both declared
585within the same class, or that the enumeration value is one of those declared
586in the \l {Qt}{Qt Namespace}.
587
588Additionally, if a C++ signal with an enum parameter should be connectable to a
589QML function using the \l{qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals}
590{connect()} function, the enum type must be registered
591using qRegisterMetaType().
592
593For QML signals, enum values may be passed as signal parameters using the \c int
594type:
595
596\qml
597 Message {
598 signal someOtherSignal(int statusValue)
599
600 Component.onCompleted: {
601 someOtherSignal(Message.Loading)
602 }
603 }
604\endqml
605
606*/