Doc: Move integration macros away from QQmlEngine reference docs

The `QtQmlIntegration` module provides the `qqmlintegration.h` header
that expose a series of macros that simplify the integration and
registration of C++ types to QML.

In the documentation, those macros are currently documented as being
provided by the `QQmlEngine` type in the `QtQml` module.

While it is true that one can access the macros by including
`QQmlEngine`, due to the header file for the type transitively including
the required header, it is only by indirection.

Furthermore, there is no real connection between a `QQmlEngine` and the
integration macros. Indeed you can use a `QQmlEngine` without
integrating any type and you can integrate types without even linking to
the `QtQml` module that provides `QtQmlEngine`.

Thus, slitghly re-organize the QML documentation to move the macros
documentation outside of the `QQmlEngine` reference documentation.

A new file, "macros.qdoc", was created under the general folder that
collects documentation related to the integration of C++ types in QML.
This new file provides a dummy documentation for the `qqmlintegration.h`
header file.

The documentation for the macros that are provided by
`qqmlintegration.h` were moved from "src/qml/doc/src/qmlfunction.qdoc"
to this new file.
Furthermore, the documentation body for each macro was modified to
"relate" to the newly documented header file, allowing them to be
positioned in under the correct element in the output documentation.

Certain links in the qmllint documentation were modified to be adapted
to the new documentation structure, as they were linking to some of the
macros by specifying their position to be under the `QQmlEngine`
documentation specifically.

A small note in the cmake documentation that mentioned the now
documented header file was modified to link to the header file
documentation itself.
In the same note, a non-linking mention to the `QML_ELEMENT`
macro was modified to link to the available documentation for the macro.

The documentation related to the definition of QML types from C++
mentioned `qqmlregistration.h` as the required header to access the
registration macros.
While this is potentially true, as the header will include
`qqmlregistration.h`, it requires linking to the fatter `QtQml` module.

As there might be cases where it is not required to link to `QtQml`
itself, mention that the macros resides in the `qqmlintegration.h`
header.

Pick-to: 6.9 6.8
Task-number: QTBUG-132409
Change-Id: I2ff9c1aa40b6d3cd6f451a4d2a7c2c10a9566f35
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
This commit is contained in:
Luca Di Sera 2025-02-19 13:18:23 +01:00
parent 7da85b0bdb
commit 4d4067a41a
7 changed files with 862 additions and 838 deletions

View File

@ -60,8 +60,8 @@ qt_generate_foreign_qml_types(mylib mylib_declarative)
\endcode
\note In the example above, \c mylib does not depend on QtQml or QtQuick, but only on the
header-only QmlIntegration target (for the QtQmlIntegration/qqmlintegration.h header, which provides
the \c QML_ELEMENT macro).
header-only QmlIntegration target (for the \l{qqmlintegration.h} header, which provides
the \l QML_ELEMENT macro).
The effect is equivalent to using \c QML_FOREIGN with custom structs in the QML library to expose
the types.

View File

@ -52,10 +52,20 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\section2 Preconditions
All the macros mentioned below are available from the \c qqmlregistration.h
header. You need to add the following code to the files using them in order to
All the macros mentioned below are available from the \l qqmlintegration.h
header file from the QtQmlIntegration module.
You need to add the following code to the files using them in order to
make the macros available:
\code
#include <QtQmlIntegration/qqmlintegration.h>
\endcode
If you are already linking to the QtQml module, you can instead use the \l
qqmlregistration.h header file, which will include \l qqmlintegration.h, as
follows:
\code
#include <QtQml/qqmlregistration.h>
\endcode

View File

@ -0,0 +1,841 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\headerfile <qqmlintegration.h>
\inmodule QtQml
\inheaderfile QtQmlIntegration/qqmlintegration.h
\title Registering C++ types to QML
This header provides macros that can be used to register C++ types with QML.
\sa qt_generate_foreign_qml_types, {Overview - QML and C++ Integration}, qmltyperegistrar
*/
/*!
\macro QML_ELEMENT
\relates qqmlintegration.h
Declares the enclosing type or namespace to be available in QML, using its
class or namespace name as the QML element name.
For example, this makes the C++ class \c Slider available as a QML type
named \c Slider. All its properties, invokable methods and enums are exposed.
\code
class Slider : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
// ...
public:
enum Slippiness {
Dry, Wet, Icy
};
Q_ENUM(Slippiness)
Q_INVOKABLE void slide(Slippiness slippiness);
// ...
}
\endcode
You can use the build system to register the type in the type namespace
\e {com.mycompany.qmlcomponents} with major version \c 1.
For qmake, specify the following in your project file:
\badcode
CONFIG += qmltypes
QML_IMPORT_NAME = com.mycompany.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1
\endcode
With CMake, you pass the URI and version to qt_add_qml_module
\badcode
qt6_add_qml_module(myapp
URI com.mycompany.qmlcomponents
VERSION 1.0
)
\endcode
Once registered, the type can be used in QML by importing the
same type namespace and version number:
\qml
import com.mycompany.qmlcomponents 1.0
Slider {
value: 12
Component.onCompleted: slide(Slider.Icy)
// ...
}
\endqml
You can also make namespaces tagged with Q_NAMESPACE available this way, in
order to expose any enums tagged with Q_ENUM_NS they contain:
\code
namespace MyNamespace {
Q_NAMESPACE
QML_ELEMENT
enum MyEnum {
Key1,
Key2,
};
Q_ENUM_NS(MyEnum)
}
\endcode
In QML, you can then use the enums:
\qml
Component.onCompleted: console.log(MyNamespace.Key2)
\endqml
\b{NOTE:} When classes have the same name but are located in different namespaces using
\l QML_ELEMENT on both of them will cause a conflict.
Make sure to use \l QML_NAMED_ELEMENT() for one of them instead.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT(),
Q_REVISION(), QML_ADDED_IN_VERSION()
*/
/*!
\macro QML_NAMED_ELEMENT(name)
\relates qqmlintegration.h
Declares the enclosing type or namespace to be available in QML, using \a name
as the element name. Otherwise behaves the same as QML_ELEMENT.
\code
class SqlEventDatabase : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(EventDatabase)
// ...
};
\endcode
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_ELEMENT
*/
/*!
\macro QML_ANONYMOUS
\relates qqmlintegration.h
Declares the enclosing type to be available, but anonymous in QML. The type
cannot be created or used to declare properties in QML, but when passed from
C++, it is recognized. In QML, you can use properties of this type if they
are declared in C++.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_INTERFACE
*/
/*!
\macro QML_INTERFACE
\relates qqmlintegration.h
This macro registers the enclosing C++ type in the QML system as an interface.
Types registered as an interface in QML should also declare themselves as an
interface with the \l {The Meta-Object System}{meta object system}. For
example:
\code
struct FooInterface
{
QML_INTERFACE
public:
virtual ~FooInterface();
virtual void doSomething() = 0;
};
Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
\endcode
When registered with QML in this way, they can be used as property types:
Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
When you assign a \l QObject sub-class to this property, the QML engine does
the interface cast to \c FooInterface* automatically.
Interface types are implicitly anonymous and uncreatable in QML.
\b{NOTE:} When inheriting from types using QML_INTERFACE, use \l QML_IMPLEMENTS_INTERFACES
instead of \l Q_INTERFACES.
\sa QML_IMPLEMENTS_INTERFACES(), QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_ANONYMOUS
*/
/*!
\macro QML_IMPLEMENTS_INTERFACES(interfaces)
\relates qqmlintegration.h
This macro tells Qt which QML \a interfaces the class implements.
This macro should only be used for interfacing with classes using \l QML_INTERFACE, use \l Q_INTERFACES otherwise.
It's required in order for declarative registration via \l QML_ELEMENT to
function properly.
\sa QML_INTERFACE, Q_INTERFACES
*/
/*!
\macro QML_UNCREATABLE(reason)
\relates qqmlintegration.h
Declares that the enclosing type shall not be creatable from QML. This takes
effect if the type is available in QML, by having a \l QML_ELEMENT or
\l QML_NAMED_ELEMENT() macro. The \a reason will be emitted as error message if an
attempt to create the type from QML is detected.
Some QML types are implicitly uncreatable, in particular types exposed with
\l QML_ANONYMOUS or namespaces exposed with \l QML_ELEMENT or
\l QML_NAMED_ELEMENT().
Since Qt 6.0 you can use "" instead of a reason to use a standard message
instead.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_ANONYMOUS
*/
/*!
\macro QML_SINGLETON
\relates qqmlintegration.h
Declares the enclosing type to be a singleton in QML. This only takes effect
if the type is a \l Q_OBJECT and is available in QML (by having a
\l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro). By default, each QQmlEngine
will try to create a singleton instance using either the type's default
constructor or a static factory function of the signature
\c{T *create(QQmlEngine *, QJSEngine *)} when the type is first accessed.
If both do exist and are accessible, the default constructor is preferred.
If there is no default constructor and no factory function the singleton is
inaccessible. The QML engine generally assumes ownership of the singleton and
will delete it when the engine itself is destroyed. You can prevent this by
calling QJSEngine::setObjectOwnership() on the singleton.
In order to declare a default-constructible class as singleton, all you have
to do is add \l QML_SINGLETON:
\code
class MySingleton : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
// Q_PROPERTY( ... )
public:
// members, Q_INVOKABLE functions, etc.
};
\endcode
If the singleton class is not default-constructible, but you can modify it,
you can add a factory function to it, in order to make it accessible:
\code
class MySingleton : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
// Q_PROPERTY( ... )
public:
static MySingleton *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
{
MySingleton *result = nullptr;
// Create the object using some custom constructor or factory.
// The QML engine will assume ownership and delete it, eventually.
return result;
}
// members, Q_INVOKABLE functions, etc
};
\endcode
If you cannot modify the class and it does not have a default constructor or a
suitable factory function, you can provide a \l QML_FOREIGN wrapper to define
the factory function:
\code
struct SingletonForeign
{
Q_GADGET
QML_FOREIGN(MySingleton)
QML_SINGLETON
QML_NAMED_ELEMENT(MySingleton)
public:
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
MySingleton *result = nullptr;
// Create the instance using some custom constructor or factory.
// The QML engine will assume ownership and delete it, eventually.
return result;
}
};
\endcode
Finally, if you want to provide one specific singleton object, the creation of
which you cannot control, you can return that from a factory function. This is
a replacement for the \l qmlRegisterSingletonInstance function.
If you were calling
\code
qmlRegisterSingletonInstance("MyModule", 1, 0, "MySingleton", myObject);
\endcode
with myObject being of type \c{MySingleton *}, you can do the following
instead:
\code
struct SingletonForeign
{
Q_GADGET
QML_FOREIGN(MySingleton)
QML_SINGLETON
QML_NAMED_ELEMENT(MySingleton)
public:
// Initialize this using myObject where you would previously
// call qmlRegisterSingletonInstance().
inline static MySingleton *s_singletonInstance = nullptr;
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(s_singletonInstance);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(engine->thread() == s_singletonInstance->thread());
// There can only be one engine accessing the singleton.
if (s_engine)
Q_ASSERT(engine == s_engine);
else
s_engine = engine;
// Explicitly specify C++ ownership so that the engine doesn't delete
// the instance.
QJSEngine::setObjectOwnership(s_singletonInstance,
QJSEngine::CppOwnership);
return s_singletonInstance;
}
private:
inline static QJSEngine *s_engine = nullptr;
};
\endcode
This way, the pre-existing class \c MySingleton is declared to be a QML
singleton, called \c MySingleton. You can specify an instance for it any time
before it is used by setting the \c s_singletonInstance member. None of this
requires modification of \c MySingleton itself.
\note This pattern doesn't work if either the singleton is accessed by
multiple QML engines, or if the QML engine accessing it has a different thread
affinity than the singleton object itself. As shown above, you can check the
parameters to the \c create() method for identity and thread affinity of the
engine in order to assert on that.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(),
qmlRegisterSingletonInstance(), QQmlEngine::singletonInstance(), {Singletons in QML}
*/
/*!
\macro QML_ADDED_IN_VERSION(MAJOR, MINOR)
\relates qqmlintegration.h
Declares that the enclosing type or namespace was added in the specified
\a{MAJOR}.\a{MINOR} version. The version is assumed to be in line with any
revisions given by \l Q_REVISION() macros on methods, slots, or signals,
and any REVISION() attributes on properties declared with \l Q_PROPERTY().
\l QML_ADDED_IN_VERSION() only takes effect if the type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
If the QML module the type belongs to is imported with a lower version than
the one determined this way, the QML type is invisible.
\sa QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_ADDED_IN_MINOR_VERSION(VERSION)
\relates qqmlintegration.h
\deprecated [6.7] Use QML_ADDED_IN_VERSION and specify the full version
Declares that the enclosing type or namespace was added in the specified minor
\a VERSION, relative to the module major version. The minor version is assumed
to be in line with any revisions given by \l Q_REVISION() macros on methods,
slots, or signals, and any REVISION() attributes on properties declared with
\l Q_PROPERTY().
\l QML_ADDED_IN_MINOR_VERSION() only takes effect if the type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
If the QML module the type belongs to is imported with a lower version than
the one determined this way, the QML type is invisible.
\sa QML_ADDED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_REMOVED_IN_VERSION(MAJOR, MINOR)
\relates qqmlintegration.h
Declares that the enclosing type or namespace was removed in the specified
\a{MAJOR}.\a{MINOR} version. This is primarily useful when replacing the
implementation of a QML type. If a corresponding \l QML_ADDED_IN_VERSION()
is present on a different type or namespace of the same QML name, then the
removed type is used when importing versions of the module lower than
\a{MAJOR}.\a{MINOR}, and the added type is used when importing
versions of the module greater or equal \a{MAJOR}.\a{MINOR}.
\l QML_REMOVED_IN_VERSION() only takes effect if type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
\sa QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_REMOVED_IN_MINOR_VERSION(VERSION)
\relates qqmlintegration.h
\deprecated [6.7] Use QML_REMOVED_IN_VERSION and specify the full version
Declares that the enclosing type or namespace was removed in the specified
minor \a VERSION, relative to the module major version. This is primarily
useful when replacing the implementation of a QML type. If a corresponding
\l QML_ADDED_IN_VERSION() is present on a different type or namespace of
the same QML name, then the removed type is used when importing versions of
the module lower than \a VERSION, and the added type is used when importing
versions of the module greater or equal \a VERSION.
\l QML_REMOVED_IN_MINOR_VERSION() only takes effect if type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
\sa QML_REMOVED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_EXTRA_VERSION(MAJOR, MINOR)
\relates qqmlintegration.h
Declare that the type should also be available in version \a{MAJOR}.\a{MINOR}.
This can be helpful if a type should be available in multiple major versions.
Types are automatically registered for:
\list
\li The major version they were introduced in, see \l{QML_ADDED_IN_VERSION}.
\li Any major versions any their members were introduced in.
\li The current major version of their module, unless they were
\l{QML_REMOVED_IN_VERSION} before that.
\endlist
Notably, they are not automatically registered in any \l{PAST_MAJOR_VERSIONS}
between the above. You can use QML_EXTRA_VERSION to manually register your
types in further major versions.
\note Keeping multiple \l{PAST_MAJOR_VERSIONS} around is computationally
expensive.
\sa QML_ELEMENT, QML_ADDED_IN_VERSION
*/
/*!
\macro QML_ATTACHED(ATTACHED_TYPE)
\relates qqmlintegration.h
Declares that the enclosing type attaches \a ATTACHED_TYPE as an
\l {Attached Properties and Attached Signal Handlers}
{attached property} to other types. This takes effect if the type
is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), qmlAttachedPropertiesObject(),
{Providing Attached Properties}
*/
/*!
\macro QML_EXTENDED(EXTENDED_TYPE)
\relates qqmlintegration.h
Declares that the enclosing type uses \a EXTENDED_TYPE as an extension to
provide further properties, methods, and enumerations in QML. This takes
effect if the type is exposed to QML using a \l QML_ELEMENT or
\l QML_NAMED_ELEMENT() macro.
\warning Members of \a EXTENDED_TYPE are implicitly treated as FINAL.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED_NAMESPACE(),
{Registering Extension Objects}
*/
/*!
\macro QML_EXTENDED_NAMESPACE(EXTENDED_NAMESPACE)
\relates qqmlintegration.h
Declares that the enclosing type uses \a EXTENDED_NAMESPACE as an extension to
provide further enumerations in QML. This takes effect if the type
is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
The enumerations need to be exposed to the metaobject system for this to work.
For example, give the following C++ code
\code
namespace MyNamespace {
Q_NAMESPACE
enum MyEnum { MyEnumerator = 10 };
Q_ENUM_NS(MyEnum)
}
class QmlType : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_EXTENDED_NAMESPACE(MyNamespace)
}
\endcode
we can access the enum in QML:
\qml
QmlType {
property int i: QmlType.MyEnumerator // i will be 10
}
\endqml
\note EXTENDED_NAMESPACE can also be a QObject or QGadget; in that case - and in contrast to
QML_EXTENDED, which also exposes methods and properties - only its enumerations
are exposed.
\note \a EXTENDED_NAMESPACE must have a metaobject; i.e. it must either be a namespace which
contains the Q_NAMESPACE macro or a QObject/QGadget.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED(),
{Registering Extension Objects}, Q_ENUM, Q_ENUM_NS
*/
/*!
\macro QML_FOREIGN(FOREIGN_TYPE)
\relates qqmlintegration.h
Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
\l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
\l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
\l QML_ADDED_IN_MINOR_VERSION(), \l QML_REMOVED_IN_MINOR_VERSION(),
\l QML_EXTENDED(), or \l QML_EXTENDED_NAMESPACE() macros
in the enclosing C++ type do not apply to the enclosing type but instead to
\a FOREIGN_TYPE. The enclosing type still needs to be registered with the
\l {The Meta-Object System}{meta object system} using a \l Q_GADGET or
\l Q_OBJECT macro.
This is useful for registering types that cannot be amended to add the macros,
for example because they belong to 3rdparty libraries.
To register a namespace, see \l QML_FOREIGN_NAMESPACE().
\note You may want to use \l QML_NAMED_ELEMENT() instead of \l QML_ELEMENT.
With QML_ELEMENT, the element is named after the struct it is contained in,
not the foreign type. The \l {Foreign objects integration} chapter in
\l {Writing advanced QML Extensions with C++} demonstrates this.
\note QML_ATTACHED() can currently not be redirected like this. It has to be
specificed in the same type that implements qmlAttachedProperties().
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN_NAMESPACE()
*/
/*!
\macro QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE)
\relates qqmlintegration.h
Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
\l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
\l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
\l QML_ADDED_IN_MINOR_VERSION(), or \l QML_REMOVED_IN_MINOR_VERSION()
macros in the enclosing C++ namespace do not apply to the enclosing type but
instead to \a FOREIGN_NAMESPACE. The enclosing namespace still needs to be
registered with the \l {The Meta-Object System}{meta object system} using a
\l Q_NAMESPACE macro.
This is useful for registering namespaces that cannot be amended to add the macros,
for example because they belong to 3rdparty libraries.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN()
*/
/*!
\macro QML_UNAVAILABLE
\relates qqmlintegration.h
This macro declares the enclosing type to be unavailable in QML. It registers
an internal dummy type called \c QQmlTypeNotAvailable as \l QML_FOREIGN()
type, using any further QML macros you specify.
Normally, the types exported by a module should be fixed. However, if a C++
type is not available, you should at least "reserve" the QML type name, and
give the user of the unavailable type a meaningful error message.
Example:
\code
#ifdef NO_GAMES_ALLOWED
struct MinehuntGame
{
Q_GADGET
QML_NAMED_ELEMENT(Game)
QML_UNAVAILABLE
QML_UNCREATABLE("Get back to work, slacker!");
};
#else
class MinehuntGame : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(Game)
// ...
};
#endif
\endcode
This will cause any QML which attempts to use the "Game" type to produce an
error message:
\badcode
fun.qml: Get back to work, slacker!
Game {
^
\endcode
Using this technique, you only need a \l Q_GADGET struct to customize the error
message, not a full-blown \l QObject. Without \l QML_UNCREATABLE(),
\l QML_UNAVAILABLE still results in a more specific error message than the usual
"is not a type" for completely unknown types.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_FOREIGN()
*/
/*!
\macro QML_SEQUENTIAL_CONTAINER(VALUE_TYPE)
\relates qqmlintegration.h
This macro declares the enclosing or referenced type as a sequential container
managing a sequence of \a VALUE_TYPE elements. \a VALUE_TYPE can be an actual
\l{QML Value Types}{value type} or a pointer to an
\l{QML Object Types}{object type}. You will rarely be able to add this macro
to the actual container declaration since containers are usually templates.
You should use \l{QML_FOREIGN} to attach the type registration to a template
instantiation. Using this technique you can, for example, declare sequential
containers like this:
\code
class IntDequeRegistration
{
Q_GADGET
QML_FOREIGN(std::deque<int>)
QML_ANONYMOUS
QML_SEQUENTIAL_CONTAINER(int)
};
\endcode
After this, you can use the container like a JavaScript array in QML.
\code
class Maze
{
Q_OBJECT
Q_ELEMENT
// 0: North, 1: East, 2: South, 3: West
Q_PROPERTY(std::deque<int> solution READ solution CONSTANT FINAL)
[...]
}
\endcode
\code
Item {
Maze {
id: maze
}
function showSolution() {
maze.solution.forEach([...])
}
}
\endcode
\note For \l{QML Value Types} \l{QList} is automatically registered as
sequential container. For \l{QML Object Types} \l{QQmlListProperty} is.
You don't have to add these registrations.
\note You cannot currently give the container a custom name. Any argument
passed to \l{QML_NAMED_ELEMENT} is ignored. The automatically registered
sequential containers are available under the familiar \e{list<...>} names,
for example \e{list<QtObject>} or \e{list<font>}.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ANONYMOUS, QML_FOREIGN()
*/
/*!
\macro QML_VALUE_TYPE(name)
\relates qqmlintegration.h
Declares the enclosing type or namespace to be available in QML, using \a name
as the name. The type has to be a value type and the name has to be lower case.
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
// ...
};
\endcode
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT
*/
/*!
\macro QML_CONSTRUCTIBLE_VALUE
\since 6.5
\relates qqmlintegration.h
Marks the surrounding value type as constructible. That is, any \l Q_INVOKABLE
constructors of the type that take exactly one argument can be used when
assigning a JavaScript value to a property of this type.
You can declare a constructible value type as follows:
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
QML_CONSTRUCTIBLE_VALUE
public:
Q_INVOKABLE MyValueType(double d);
// ...
};
\endcode
With the above type, the following QML code will produce a \c MyValueType
value using the given constructor and assign it to the property.
\qml
QtObject {
property myValueType v: 5.4
}
\endqml
You can also construct lists of values this way:
\qml
QtObject {
property list<myValueType> v: [5.4, 4.5, 3.3]
}
\endqml
If you make value types \l{ValueTypeBehavior}{addressable}, you can
use such a type in a \l{Type annotations and assertions}{type assertion}
to explicitly construct it:
\qml
pragma ValueTypeBehavior: Addressable
QtObject {
function process(d: real) {
let v = d as myValueType;
// v is a myValueType now, not a number
}
}
\endqml
\sa QML_VALUE_TYPE
*/
/*!
\macro QML_STRUCTURED_VALUE
\since 6.5
\relates qqmlintegration.h
Marks the surrounding value type as structured. Structured value types can
and will preferably be constructed property-by-property from a JavaScript
object. A structured value type, however is always \l QML_CONSTRUCTIBLE_VALUE,
too. This means, you can still provide \l Q_INVOKABLE constructors in order to
handle construction from primitive types.
You can declare a structured value type as follows:
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
QML_STRUCTURED_VALUE
Q_PROPERTY(double d READ d WRITE setD)
Q_PROPERTY(string e READ e WRITE setE)
// ...
};
\endcode
Then you can populate a property of this type as follows:
\qml
QtObject {
property myValueType v: ({d: 4.4, e: "a string"})
}
\endqml
The extra parentheses are necessary to disambiguate the JavaScript object
from what might be interpreted as a JavaScript code block.
You can also construct lists of values this way:
\qml
QtObject {
property list<myValueType> v: [
{d: 4.4, e: "a string"},
{d: 7.1, e: "another string"}
]
}
\endqml
If you make value types \l{ValueTypeBehavior}{addressable}, you can
use such a type in a \l{Type annotations and assertions}{type assertion}
to explicitly construct it:
\qml
pragma ValueTypeBehavior: Addressable
QtObject {
function process(d: real) {
let v = {d: d, e: objectName} as myValueType;
// v is a myValueType now
}
}
\endqml
\sa QML_VALUE_TYPE QML_CONSTRUCTIBLE_VALUE
*/

View File

@ -1,689 +1,6 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\macro QML_ELEMENT
\relates QQmlEngine
Declares the enclosing type or namespace to be available in QML, using its
class or namespace name as the QML element name.
For example, this makes the C++ class \c Slider available as a QML type
named \c Slider. All its properties, invokable methods and enums are exposed.
\code
class Slider : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
// ...
public:
enum Slippiness {
Dry, Wet, Icy
};
Q_ENUM(Slippiness)
Q_INVOKABLE void slide(Slippiness slippiness);
// ...
}
\endcode
You can use the build system to register the type in the type namespace
\e {com.mycompany.qmlcomponents} with major version \c 1.
For qmake, specify the following in your project file:
\badcode
CONFIG += qmltypes
QML_IMPORT_NAME = com.mycompany.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1
\endcode
With CMake, you pass the URI and version to qt_add_qml_module
\badcode
qt6_add_qml_module(myapp
URI com.mycompany.qmlcomponents
VERSION 1.0
)
\endcode
Once registered, the type can be used in QML by importing the
same type namespace and version number:
\qml
import com.mycompany.qmlcomponents 1.0
Slider {
value: 12
Component.onCompleted: slide(Slider.Icy)
// ...
}
\endqml
You can also make namespaces tagged with Q_NAMESPACE available this way, in
order to expose any enums tagged with Q_ENUM_NS they contain:
\code
namespace MyNamespace {
Q_NAMESPACE
QML_ELEMENT
enum MyEnum {
Key1,
Key2,
};
Q_ENUM_NS(MyEnum)
}
\endcode
In QML, you can then use the enums:
\qml
Component.onCompleted: console.log(MyNamespace.Key2)
\endqml
\b{NOTE:} When classes have the same name but are located in different namespaces using
\l QML_ELEMENT on both of them will cause a conflict.
Make sure to use \l QML_NAMED_ELEMENT() for one of them instead.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT(),
Q_REVISION(), QML_ADDED_IN_VERSION()
*/
/*!
\macro QML_NAMED_ELEMENT(name)
\relates QQmlEngine
Declares the enclosing type or namespace to be available in QML, using \a name
as the element name. Otherwise behaves the same as QML_ELEMENT.
\code
class SqlEventDatabase : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(EventDatabase)
// ...
};
\endcode
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_ELEMENT
*/
/*!
\macro QML_ANONYMOUS
\relates QQmlEngine
Declares the enclosing type to be available, but anonymous in QML. The type
cannot be created or used to declare properties in QML, but when passed from
C++, it is recognized. In QML, you can use properties of this type if they
are declared in C++.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_INTERFACE
*/
/*!
\macro QML_INTERFACE
\relates QQmlEngine
This macro registers the enclosing C++ type in the QML system as an interface.
Types registered as an interface in QML should also declare themselves as an
interface with the \l {The Meta-Object System}{meta object system}. For
example:
\code
struct FooInterface
{
QML_INTERFACE
public:
virtual ~FooInterface();
virtual void doSomething() = 0;
};
Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
\endcode
When registered with QML in this way, they can be used as property types:
Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
When you assign a \l QObject sub-class to this property, the QML engine does
the interface cast to \c FooInterface* automatically.
Interface types are implicitly anonymous and uncreatable in QML.
\b{NOTE:} When inheriting from types using QML_INTERFACE, use \l QML_IMPLEMENTS_INTERFACES
instead of \l Q_INTERFACES.
\sa QML_IMPLEMENTS_INTERFACES(), QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_ANONYMOUS
*/
/*!
\macro QML_IMPLEMENTS_INTERFACES(interfaces)
\relates QQmlEngine
This macro tells Qt which QML \a interfaces the class implements.
This macro should only be used for interfacing with classes using \l QML_INTERFACE, use \l Q_INTERFACES otherwise.
It's required in order for declarative registration via \l QML_ELEMENT to
function properly.
\sa QML_INTERFACE, Q_INTERFACES
*/
/*!
\macro QML_UNCREATABLE(reason)
\relates QQmlEngine
Declares that the enclosing type shall not be creatable from QML. This takes
effect if the type is available in QML, by having a \l QML_ELEMENT or
\l QML_NAMED_ELEMENT() macro. The \a reason will be emitted as error message if an
attempt to create the type from QML is detected.
Some QML types are implicitly uncreatable, in particular types exposed with
\l QML_ANONYMOUS or namespaces exposed with \l QML_ELEMENT or
\l QML_NAMED_ELEMENT().
Since Qt 6.0 you can use "" instead of a reason to use a standard message
instead.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_ANONYMOUS
*/
/*!
\macro QML_SINGLETON
\relates QQmlEngine
Declares the enclosing type to be a singleton in QML. This only takes effect
if the type is a \l Q_OBJECT and is available in QML (by having a
\l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro). By default, each QQmlEngine
will try to create a singleton instance using either the type's default
constructor or a static factory function of the signature
\c{T *create(QQmlEngine *, QJSEngine *)} when the type is first accessed.
If both do exist and are accessible, the default constructor is preferred.
If there is no default constructor and no factory function the singleton is
inaccessible. The QML engine generally assumes ownership of the singleton and
will delete it when the engine itself is destroyed. You can prevent this by
calling QJSEngine::setObjectOwnership() on the singleton.
In order to declare a default-constructible class as singleton, all you have
to do is add \l QML_SINGLETON:
\code
class MySingleton : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
// Q_PROPERTY( ... )
public:
// members, Q_INVOKABLE functions, etc.
};
\endcode
If the singleton class is not default-constructible, but you can modify it,
you can add a factory function to it, in order to make it accessible:
\code
class MySingleton : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
// Q_PROPERTY( ... )
public:
static MySingleton *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
{
MySingleton *result = nullptr;
// Create the object using some custom constructor or factory.
// The QML engine will assume ownership and delete it, eventually.
return result;
}
// members, Q_INVOKABLE functions, etc
};
\endcode
If you cannot modify the class and it does not have a default constructor or a
suitable factory function, you can provide a \l QML_FOREIGN wrapper to define
the factory function:
\code
struct SingletonForeign
{
Q_GADGET
QML_FOREIGN(MySingleton)
QML_SINGLETON
QML_NAMED_ELEMENT(MySingleton)
public:
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
MySingleton *result = nullptr;
// Create the instance using some custom constructor or factory.
// The QML engine will assume ownership and delete it, eventually.
return result;
}
};
\endcode
Finally, if you want to provide one specific singleton object, the creation of
which you cannot control, you can return that from a factory function. This is
a replacement for the \l qmlRegisterSingletonInstance function.
If you were calling
\code
qmlRegisterSingletonInstance("MyModule", 1, 0, "MySingleton", myObject);
\endcode
with myObject being of type \c{MySingleton *}, you can do the following
instead:
\code
struct SingletonForeign
{
Q_GADGET
QML_FOREIGN(MySingleton)
QML_SINGLETON
QML_NAMED_ELEMENT(MySingleton)
public:
// Initialize this using myObject where you would previously
// call qmlRegisterSingletonInstance().
inline static MySingleton *s_singletonInstance = nullptr;
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(s_singletonInstance);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(engine->thread() == s_singletonInstance->thread());
// There can only be one engine accessing the singleton.
if (s_engine)
Q_ASSERT(engine == s_engine);
else
s_engine = engine;
// Explicitly specify C++ ownership so that the engine doesn't delete
// the instance.
QJSEngine::setObjectOwnership(s_singletonInstance,
QJSEngine::CppOwnership);
return s_singletonInstance;
}
private:
inline static QJSEngine *s_engine = nullptr;
};
\endcode
This way, the pre-existing class \c MySingleton is declared to be a QML
singleton, called \c MySingleton. You can specify an instance for it any time
before it is used by setting the \c s_singletonInstance member. None of this
requires modification of \c MySingleton itself.
\note This pattern doesn't work if either the singleton is accessed by
multiple QML engines, or if the QML engine accessing it has a different thread
affinity than the singleton object itself. As shown above, you can check the
parameters to the \c create() method for identity and thread affinity of the
engine in order to assert on that.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(),
qmlRegisterSingletonInstance(), QQmlEngine::singletonInstance(), {Singletons in QML}
*/
/*!
\macro QML_ADDED_IN_VERSION(MAJOR, MINOR)
\relates QQmlEngine
Declares that the enclosing type or namespace was added in the specified
\a{MAJOR}.\a{MINOR} version. The version is assumed to be in line with any
revisions given by \l Q_REVISION() macros on methods, slots, or signals,
and any REVISION() attributes on properties declared with \l Q_PROPERTY().
\l QML_ADDED_IN_VERSION() only takes effect if the type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
If the QML module the type belongs to is imported with a lower version than
the one determined this way, the QML type is invisible.
\sa QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_ADDED_IN_MINOR_VERSION(VERSION)
\relates QQmlEngine
\deprecated [6.7] Use QML_ADDED_IN_VERSION and specify the full version
Declares that the enclosing type or namespace was added in the specified minor
\a VERSION, relative to the module major version. The minor version is assumed
to be in line with any revisions given by \l Q_REVISION() macros on methods,
slots, or signals, and any REVISION() attributes on properties declared with
\l Q_PROPERTY().
\l QML_ADDED_IN_MINOR_VERSION() only takes effect if the type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
If the QML module the type belongs to is imported with a lower version than
the one determined this way, the QML type is invisible.
\sa QML_ADDED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_REMOVED_IN_VERSION(MAJOR, MINOR)
\relates QQmlEngine
Declares that the enclosing type or namespace was removed in the specified
\a{MAJOR}.\a{MINOR} version. This is primarily useful when replacing the
implementation of a QML type. If a corresponding \l QML_ADDED_IN_VERSION()
is present on a different type or namespace of the same QML name, then the
removed type is used when importing versions of the module lower than
\a{MAJOR}.\a{MINOR}, and the added type is used when importing
versions of the module greater or equal \a{MAJOR}.\a{MINOR}.
\l QML_REMOVED_IN_VERSION() only takes effect if type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
\sa QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_REMOVED_IN_MINOR_VERSION(VERSION)
\relates QQmlEngine
\deprecated [6.7] Use QML_REMOVED_IN_VERSION and specify the full version
Declares that the enclosing type or namespace was removed in the specified
minor \a VERSION, relative to the module major version. This is primarily
useful when replacing the implementation of a QML type. If a corresponding
\l QML_ADDED_IN_VERSION() is present on a different type or namespace of
the same QML name, then the removed type is used when importing versions of
the module lower than \a VERSION, and the added type is used when importing
versions of the module greater or equal \a VERSION.
\l QML_REMOVED_IN_MINOR_VERSION() only takes effect if type or namespace is
available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
\l QML_ANONYMOUS, or \l QML_INTERFACE macro.
\sa QML_REMOVED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
*/
/*!
\macro QML_EXTRA_VERSION(MAJOR, MINOR)
\relates QQmlEngine
Declare that the type should also be available in version \a{MAJOR}.\a{MINOR}.
This can be helpful if a type should be available in multiple major versions.
Types are automatically registered for:
\list
\li The major version they were introduced in, see \l{QML_ADDED_IN_VERSION}.
\li Any major versions any their members were introduced in.
\li The current major version of their module, unless they were
\l{QML_REMOVED_IN_VERSION} before that.
\endlist
Notably, they are not automatically registered in any \l{PAST_MAJOR_VERSIONS}
between the above. You can use QML_EXTRA_VERSION to manually register your
types in further major versions.
\note Keeping multiple \l{PAST_MAJOR_VERSIONS} around is computationally
expensive.
\sa QML_ELEMENT, QML_ADDED_IN_VERSION
*/
/*!
\macro QML_ATTACHED(ATTACHED_TYPE)
\relates QQmlEngine
Declares that the enclosing type attaches \a ATTACHED_TYPE as an
\l {Attached Properties and Attached Signal Handlers}
{attached property} to other types. This takes effect if the type
is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), qmlAttachedPropertiesObject(),
{Providing Attached Properties}
*/
/*!
\macro QML_EXTENDED(EXTENDED_TYPE)
\relates QQmlEngine
Declares that the enclosing type uses \a EXTENDED_TYPE as an extension to
provide further properties, methods, and enumerations in QML. This takes
effect if the type is exposed to QML using a \l QML_ELEMENT or
\l QML_NAMED_ELEMENT() macro.
\warning Members of \a EXTENDED_TYPE are implicitly treated as FINAL.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED_NAMESPACE(),
{Registering Extension Objects}
*/
/*!
\macro QML_EXTENDED_NAMESPACE(EXTENDED_NAMESPACE)
\relates QQmlEngine
Declares that the enclosing type uses \a EXTENDED_NAMESPACE as an extension to
provide further enumerations in QML. This takes effect if the type
is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
The enumerations need to be exposed to the metaobject system for this to work.
For example, give the following C++ code
\code
namespace MyNamespace {
Q_NAMESPACE
enum MyEnum { MyEnumerator = 10 };
Q_ENUM_NS(MyEnum)
}
class QmlType : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_EXTENDED_NAMESPACE(MyNamespace)
}
\endcode
we can access the enum in QML:
\qml
QmlType {
property int i: QmlType.MyEnumerator // i will be 10
}
\endqml
\note EXTENDED_NAMESPACE can also be a QObject or QGadget; in that case - and in contrast to
QML_EXTENDED, which also exposes methods and properties - only its enumerations
are exposed.
\note \a EXTENDED_NAMESPACE must have a metaobject; i.e. it must either be a namespace which
contains the Q_NAMESPACE macro or a QObject/QGadget.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED(),
{Registering Extension Objects}, Q_ENUM, Q_ENUM_NS
*/
/*!
\macro QML_FOREIGN(FOREIGN_TYPE)
\relates QQmlEngine
Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
\l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
\l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
\l QML_ADDED_IN_MINOR_VERSION(), \l QML_REMOVED_IN_MINOR_VERSION(),
\l QML_EXTENDED(), or \l QML_EXTENDED_NAMESPACE() macros
in the enclosing C++ type do not apply to the enclosing type but instead to
\a FOREIGN_TYPE. The enclosing type still needs to be registered with the
\l {The Meta-Object System}{meta object system} using a \l Q_GADGET or
\l Q_OBJECT macro.
This is useful for registering types that cannot be amended to add the macros,
for example because they belong to 3rdparty libraries.
To register a namespace, see \l QML_FOREIGN_NAMESPACE().
\note You may want to use \l QML_NAMED_ELEMENT() instead of \l QML_ELEMENT.
With QML_ELEMENT, the element is named after the struct it is contained in,
not the foreign type. The \l {Foreign objects integration} chapter in
\l {Writing advanced QML Extensions with C++} demonstrates this.
\note QML_ATTACHED() can currently not be redirected like this. It has to be
specificed in the same type that implements qmlAttachedProperties().
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN_NAMESPACE()
*/
/*!
\macro QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE)
\relates QQmlEngine
Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
\l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
\l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
\l QML_ADDED_IN_MINOR_VERSION(), or \l QML_REMOVED_IN_MINOR_VERSION()
macros in the enclosing C++ namespace do not apply to the enclosing type but
instead to \a FOREIGN_NAMESPACE. The enclosing namespace still needs to be
registered with the \l {The Meta-Object System}{meta object system} using a
\l Q_NAMESPACE macro.
This is useful for registering namespaces that cannot be amended to add the macros,
for example because they belong to 3rdparty libraries.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN()
*/
/*!
\macro QML_UNAVAILABLE
\relates QQmlEngine
This macro declares the enclosing type to be unavailable in QML. It registers
an internal dummy type called \c QQmlTypeNotAvailable as \l QML_FOREIGN()
type, using any further QML macros you specify.
Normally, the types exported by a module should be fixed. However, if a C++
type is not available, you should at least "reserve" the QML type name, and
give the user of the unavailable type a meaningful error message.
Example:
\code
#ifdef NO_GAMES_ALLOWED
struct MinehuntGame
{
Q_GADGET
QML_NAMED_ELEMENT(Game)
QML_UNAVAILABLE
QML_UNCREATABLE("Get back to work, slacker!");
};
#else
class MinehuntGame : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(Game)
// ...
};
#endif
\endcode
This will cause any QML which attempts to use the "Game" type to produce an
error message:
\badcode
fun.qml: Get back to work, slacker!
Game {
^
\endcode
Using this technique, you only need a \l Q_GADGET struct to customize the error
message, not a full-blown \l QObject. Without \l QML_UNCREATABLE(),
\l QML_UNAVAILABLE still results in a more specific error message than the usual
"is not a type" for completely unknown types.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_FOREIGN()
*/
/*!
\macro QML_SEQUENTIAL_CONTAINER(VALUE_TYPE)
\relates QQmlEngine
This macro declares the enclosing or referenced type as a sequential container
managing a sequence of \a VALUE_TYPE elements. \a VALUE_TYPE can be an actual
\l{QML Value Types}{value type} or a pointer to an
\l{QML Object Types}{object type}. You will rarely be able to add this macro
to the actual container declaration since containers are usually templates.
You should use \l{QML_FOREIGN} to attach the type registration to a template
instantiation. Using this technique you can, for example, declare sequential
containers like this:
\code
class IntDequeRegistration
{
Q_GADGET
QML_FOREIGN(std::deque<int>)
QML_ANONYMOUS
QML_SEQUENTIAL_CONTAINER(int)
};
\endcode
After this, you can use the container like a JavaScript array in QML.
\code
class Maze
{
Q_OBJECT
Q_ELEMENT
// 0: North, 1: East, 2: South, 3: West
Q_PROPERTY(std::deque<int> solution READ solution CONSTANT FINAL)
[...]
}
\endcode
\code
Item {
Maze {
id: maze
}
function showSolution() {
maze.solution.forEach([...])
}
}
\endcode
\note For \l{QML Value Types} \l{QList} is automatically registered as
sequential container. For \l{QML Object Types} \l{QQmlListProperty} is.
You don't have to add these registrations.
\note You cannot currently give the container a custom name. Any argument
passed to \l{QML_NAMED_ELEMENT} is ignored. The automatically registered
sequential containers are available under the familiar \e{list<...>} names,
for example \e{list<QtObject>} or \e{list<font>}.
\include {qualified-class-name.qdocinc} {class name must be qualified}
\sa QML_ANONYMOUS, QML_FOREIGN()
*/
/*!
\macro QML_DECLARE_TYPE()
\relates QQmlEngine
@ -691,6 +8,7 @@
Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
*/
/*!
\macro QML_DECLARE_TYPEINFO(Type,Flags)
\relates QQmlEngine
@ -704,6 +22,7 @@
QML_ATTACHED macro.
*/
/*!
\fn void qmlClearTypeRegistrations()
\relates QQmlEngine
@ -1465,148 +784,3 @@
\sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
*/
/*!
\macro QML_VALUE_TYPE(name)
\relates QQmlEngine
Declares the enclosing type or namespace to be available in QML, using \a name
as the name. The type has to be a value type and the name has to be lower case.
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
// ...
};
\endcode
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT
*/
/*!
\macro QML_CONSTRUCTIBLE_VALUE
\since 6.5
\relates QQmlEngine
Marks the surrounding value type as constructible. That is, any \l Q_INVOKABLE
constructors of the type that take exactly one argument can be used when
assigning a JavaScript value to a property of this type.
You can declare a constructible value type as follows:
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
QML_CONSTRUCTIBLE_VALUE
public:
Q_INVOKABLE MyValueType(double d);
// ...
};
\endcode
With the above type, the following QML code will produce a \c MyValueType
value using the given constructor and assign it to the property.
\qml
QtObject {
property myValueType v: 5.4
}
\endqml
You can also construct lists of values this way:
\qml
QtObject {
property list<myValueType> v: [5.4, 4.5, 3.3]
}
\endqml
If you make value types \l{ValueTypeBehavior}{addressable}, you can
use such a type in a \l{Type annotations and assertions}{type assertion}
to explicitly construct it:
\qml
pragma ValueTypeBehavior: Addressable
QtObject {
function process(d: real) {
let v = d as myValueType;
// v is a myValueType now, not a number
}
}
\endqml
\sa QML_VALUE_TYPE
*/
/*!
\macro QML_STRUCTURED_VALUE
\since 6.5
\relates QQmlEngine
Marks the surrounding value type as structured. Structured value types can
and will preferably be constructed property-by-property from a JavaScript
object. A structured value type, however is always \l QML_CONSTRUCTIBLE_VALUE,
too. This means, you can still provide \l Q_INVOKABLE constructors in order to
handle construction from primitive types.
You can declare a structured value type as follows:
\code
class MyValueType
{
Q_GADGET
QML_VALUE_TYPE(myValueType)
QML_STRUCTURED_VALUE
Q_PROPERTY(double d READ d WRITE setD)
Q_PROPERTY(string e READ e WRITE setE)
// ...
};
\endcode
Then you can populate a property of this type as follows:
\qml
QtObject {
property myValueType v: ({d: 4.4, e: "a string"})
}
\endqml
The extra parentheses are necessary to disambiguate the JavaScript object
from what might be interpreted as a JavaScript code block.
You can also construct lists of values this way:
\qml
QtObject {
property list<myValueType> v: [
{d: 4.4, e: "a string"},
{d: 7.1, e: "another string"}
]
}
\endqml
If you make value types \l{ValueTypeBehavior}{addressable}, you can
use such a type in a \l{Type annotations and assertions}{type assertion}
to explicitly construct it:
\qml
pragma ValueTypeBehavior: Addressable
QtObject {
function process(d: real) {
let v = {d: d, e: objectName} as myValueType;
// v is a myValueType now
}
}
\endqml
\sa QML_VALUE_TYPE QML_CONSTRUCTIBLE_VALUE
*/

View File

@ -98,7 +98,7 @@ Item {
\section1 Construction from string is deprecated; Use structured value type construction instead
\section2 What happened?
You constructed a \l{QQmlEngine::}{QML_STRUCTURED_VALUE} using a string.
You constructed a QML_STRUCTURED_VALUE using a string.
\section2 Why is this bad?
This is deprecated and prone to typos.
@ -113,8 +113,7 @@ Item {
\endqml
To fix this warning, populate the structured value type as explained in the
\l{QQmlEngine::}{QML_STRUCTURED_VALUE} description instead of binding a string
to the property:
QML_STRUCTURED_VALUE description instead of binding a string to the property:
\qml
import QtQuick

View File

@ -22,7 +22,7 @@ actually installed, and that their modules end up in an
The warning might also indicate that the type of the property referenced by the alias does not have
a QML counterpart. The referenced property type might be missing the
\l{QQmlEngine::}{QML_ELEMENT} macro, for example. Refer to
QML_ELEMENT macro, for example. Refer to
\l{Defining QML Types from C++} or \l{Overview - QML and C++ Integration} in this case.
\section2 Why is this bad?
@ -131,7 +131,7 @@ actually installed, and that their modules end up in an
The warning might also indicate that the type of the property does not have
a QML counterpart. The property type might be missing the
\l{QQmlEngine::}{QML_ELEMENT} macro, for example. Refer to
QML_ELEMENT macro, for example. Refer to
\l{Defining QML Types from C++} or \l{Overview - QML and C++ Integration} in this case.
\section2 Why is this bad?

View File

@ -68,7 +68,7 @@ Item {
\section2 What happened?
You tried to instantiate a QML object from an
\l{QQmlEngine::QML_UNCREATABLE}{uncreatable type}.
\l{QML_UNCREATABLE}{uncreatable type}.
\section2 Why is this bad?
Uncreatable types are specifically marked to forbid instantiations.