<qqmlintegration.h>

Header: #include <QtQmlIntegration/qqmlintegration.h>

宏

详细说明

此头文件提供了可用于在 QML 中注册 C++ 类型的宏。

另请参阅 qt_generate_foreign_qml_types()、概述 - QML 与 C++ 集成,以及qmltyperegistrar。

宏文档

QML_ADDED_IN_VERSION(MAJOR, MINOR)

声明该外围类型或命名空间是在指定的MAJOR 版本中添加的。MINOR 。该版本被视为与方法、槽或信号上由Q_REVISION() 宏指定的任何修订版本一致,也与使用Q_PROPERTY() 声明的属性上的任何 REVISION() 属性一致。

QML_ADDED_IN_VERSION() 仅在类型或命名空间在 QML 中可用时才生效,即该类型或命名空间具有QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_ANONYMOUS 或QML_INTERFACE 宏。

如果该类型所属的 QML 模块被导入的版本低于通过此方式确定的版本,则该 QML 类型将不可见。

另请参阅 QML_ELEMENT 和QML_NAMED_ELEMENT 。

QML_ANONYMOUS

声明该外围类型在 QML 中可用,但为匿名类型。该类型无法在 QML 中创建或用于声明属性,但在从 C++ 传递时会被识别。在 QML 中,如果该类型的属性已在 C++ 中声明,则可以使用这些属性。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_UNCREATABLE() 以及QML_INTERFACE 。

QML_ATTACHED(ATTACHED_TYPE)

声明该外围类型将ATTACHED_TYPE 作为附加属性附加到其他类型上。如果该类型通过QML_ELEMENT 或QML_NAMED_ELEMENT()宏暴露给QML,则此声明生效。

注意:类名 必须是完全限定的,即使您已经处于该命名空间内也是如此。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT()、qmlAttachedPropertiesObject() 以及《提供附加属性》。

[since 6.5] QML_CONSTRUCTIBLE_VALUE

将周围的值类型标记为可构造的。也就是说,当将一个 JavaScript 值赋值给该类型的属性时,可以使用该类型中任何接受恰好一个参数的Q_INVOKABLE 构造函数。

您可以按以下方式声明可构造的值类型:

class MyValueType
{
    Q_GADGET
    QML_VALUE_TYPE(myValueType)
    QML_CONSTRUCTIBLE_VALUE
public:
    Q_INVOKABLE MyValueType(double d);

    // ...
};

对于上述类型,以下 QML 代码将使用给定的构造函数生成一个MyValueType 值,并将其赋值给该属性。

QtObject {
    property myValueType v: 5.4
}

您还可以通过这种方式构造值列表:

QtObject {
    property list<myValueType> v: [5.4, 4.5, 3.3]
}

自 Qt 6.8 起,如果您将该值类型所属的 Qml 模块导入到某个命名空间中,即可使用 JavaScript 的 `new ` 运算符对其进行实例化。

import MyModule as MM

QtObject {
    function process(d: real) {
        let v = new MM.myValueType(d);
        // v is a myValueType now
    }
}

该宏在 Qt 6.5 中引入。

另请参阅 QML_VALUE_TYPE 。

QML_ELEMENT

声明外围类型或命名空间可在 QML 中使用,并以其类名或命名空间名称作为 QML 元素名称。

例如,这会使 C++ 类 `Slider ` 作为名为 `Slider` 的 QML 类型提供。该类的所有属性、可调用方法和枚举均被公开。

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);

    // ...
}

您可以使用构建系统将该类型注册到类型命名空间`com.mycompany.qmlcomponents` 中,主版本号为 `1`。对于 qmake,请在项目文件中指定以下内容:

CONFIG += qmltypes
QML_IMPORT_NAME = com.mycompany.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1

使用 CMake 时,需将 URI 和版本号传递给 `qt_add_qml_module()`

qt_add_qml_module(myapp
  URI com.mycompany.qmlcomponents
  VERSION 1.0
)

注册完成后,可在 QML 中通过导入相同的类型命名空间和版本号来使用该类型:

import com.mycompany.qmlcomponents 1.0

Slider {
    value: 12
    Component.onCompleted: slide(Slider.Icy)

    // ...
}

您还可以通过这种方式提供标记为Q_NAMESPACE 的命名空间,以便暴露其中标记为Q_ENUM_NS 的任何枚举:

namespace MyNamespace {
  Q_NAMESPACE
  QML_ELEMENT

  enum MyEnum {
      Key1,
      Key2,
  };
  Q_ENUM_NS(MyEnum)
}

随后,您可以在 QML 中使用这些枚举:

Component.onCompleted: console.log(MyNamespace.Key2)

注意:当类名称相同但位于不同命名空间时,对两者同时使用 QML_ELEMENT 会导致冲突。请确保对其中一个类改用QML_NAMED_ELEMENT()。

注意: 类名必须使用完全限定形式,即使您已处于该命名空间内也是如此。

另请参阅 《选择 C++ 与 QML 之间的正确集成方法》、《QML_NAMED_ELEMENT()》、《Q_REVISION()》以及《QML_ADDED_IN_VERSION()》。

QML_EXTENDED(EXTENDED_TYPE)

声明该外围类型使用EXTENDED_TYPE 作为扩展,以便在QML中提供额外的属性、方法和枚举。如果通过QML_ELEMENT 或QML_NAMED_ELEMENT()宏将该类型暴露给QML,则此声明生效。

警告: EXTENDED_TYPE 的成员 会被隐式地视为 FINAL。

注意:类名 必须是完全限定的,即使您已经处于该命名空间内。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_EXTENDED_NAMESPACE() 以及“注册扩展对象”。

QML_EXTENDED_NAMESPACE(EXTENSION_NAMESPACE)

声明该外围类型使用EXTENSION_NAMESPACE 作为扩展,以便在QML中提供更多枚举。如果通过QML_ELEMENT 或QML_NAMED_ELEMENT()宏将该类型暴露给QML,则此设置生效。要使此功能生效,这些枚举必须暴露给元对象系统。

例如,假设有以下 C++ 代码

namespace MyNamespace {
    Q_NAMESPACE
    enum MyEnum { MyEnumerator = 10 };
    Q_ENUM_NS(MyEnum)
}

class QmlType : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_EXTENDED_NAMESPACE(MyNamespace)
}

我们可以在 QML 中访问该枚举:

QmlType {
    property int i: QmlType.MyEnumerator // i will be 10
}

注意: EXTENSION_NAMESPACE 也可以是QObject 或 QGadget;在这种情况下——与同样会暴露方法和属性的QML_EXTENDED 不同——仅会暴露其枚举。

注意: EXTENSION_NAMESPACE 必须具有元对象;即它必须是一个包含Q_NAMESPACE 宏的命名空间,或者是一个QObject/QGadget。

注意:类名 必须是完全限定的,即使你已经位于该命名空间内也是如此。

另请参阅 QML_NAMESPACE_EXTENDED()、QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_EXTENDED()、《扩展对象的注册》、Q_ENUM 以及Q_ENUM_NS 。

QML_EXTRA_VERSION(MAJOR, MINOR)

声明该类型也应在版本MAJOR 中可用。MINOR 。如果某个类型需要在多个主版本中可用,此操作会很有帮助。

类型会自动注册到:

需要注意的是,它们不会自动注册在上述版本之间的任何PAST_MAJOR_VERSIONS中。您可以使用 QML_EXTRA_VERSION 手动将类型注册到其他主版本中。

注意:保留 多个PAST_MAJOR_VERSIONS会消耗大量计算资源。

另请参阅 QML_ELEMENT 和QML_ADDED_IN_VERSION 。

QML_FOREIGN(FOREIGN_TYPE)

声明:外围 C++ 类型中的任何QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_ANONYMOUS 、QML_INTERFACE 、QML_UNCREATABLE()、QML_SINGLETON、QML_ADDED_IN_VERSION()、QML_REMOVED_IN_VERSION()、QML_ADDED_IN_MINOR_VERSION()、QML_REMOVED_IN_MINOR_VERSION()、QML_EXTENDED()、QML_EXTENDED_NAMESPACE() 或QML_NAMESPACE_EXTENDED() 宏均不适用于该外围类型,而是适用于FOREIGN_TYPE 。 外围类型仍需通过Q_GADGET 或Q_OBJECT 宏向元对象系统进行注册。

这对于注册无法通过修改来添加这些宏的类型非常有用,例如因为它们属于第三方库。要注册命名空间,请参阅QML_FOREIGN_NAMESPACE()。

注意:建议使用 QML_NAMED_ELEMENT() 代替QML_ELEMENT 。使用QML_ELEMENT 时,元素的名称将取自其所属的结构体,而非外部类型。这在《使用 C++ 编写高级 QML 扩展》一书的“外部对象集成”章节中有详细说明。

注意: 目前无法像这样重定向` QML_ATTACHED()`。它必须指定为实现 `qmlAttachedProperties()` 的同一类型。

注意: 即使您已处于命名空间内,类名 仍需使用完全限定形式。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT() 和QML_FOREIGN_NAMESPACE()。

QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE)

声明,在包含的 C++ 命名空间中,任何QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_ANONYMOUS 、QML_INTERFACE 、QML_UNCREATABLE()、QML_SINGLETON、QML_ADDED_IN_VERSION()、QML_REMOVED_IN_VERSION()、QML_ADDED_IN_MINOR_VERSION() 或QML_REMOVED_IN_MINOR_VERSION() 宏均不适用于该包含的类型,而是适用于FOREIGN_NAMESPACE 。 外围命名空间仍需使用Q_NAMESPACE 宏在元对象系统中进行注册。

这对于注册无法修改以添加宏的命名空间非常有用,例如因为它们属于第三方库。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT() 和QML_FOREIGN()。

QML_IMPLEMENTS_INTERFACES(interfaces)

该宏用于告知 Qt 该类实现了哪个 QMLinterfaces 。此宏仅应用于通过QML_INTERFACE 与类进行交互的情况,否则请使用Q_INTERFACES 。为了使通过QML_ELEMENT 进行的声明式注册能够正常工作,必须使用此宏。

另请参阅 QML_INTERFACE 和Q_INTERFACES 。

QML_INTERFACE

该宏将外围的 C++ 类型在 QML 系统中注册为接口。

在 QML 中注册为接口的类型,还应向元对象系统声明自身为接口。例如:

struct FooInterface
{
    QML_INTERFACE
public:
    virtual ~FooInterface();
    virtual void doSomething() = 0;
};

Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")

以这种方式在 QML 中注册后,它们即可作为属性类型使用:

Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)

当您将QObject 的子类赋值给此属性时,QML引擎会自动将该类型转换为FooInterface* 。

在 QML 中,接口类型默认是匿名的,且无法被创建。

注意:当使用 QML_INTERFACE 从类型继承时,请使用 `QML_IMPLEMENTS_INTERFACES ` 而不是 `Q_INTERFACES`。

另请参阅 QML_IMPLEMENTS_INTERFACES()、QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_UNCREATABLE() 和QML_ANONYMOUS 。

QML_NAMED_ELEMENT(name)

声明外围类型或命名空间可在 QML 中使用,并将元素名称设为name 。除此之外,其行为与QML_ELEMENT 相同。

class SqlEventDatabase : public QObject
{
    Q_OBJECT
    QML_NAMED_ELEMENT(EventDatabase)

    // ...
};

另请参阅 《选择 C++ 与 QML 之间的正确集成方法》和《QML_ELEMENT 》。

QML_REMOVED_IN_VERSION(MAJOR, MINOR)

声明在指定的MAJOR.MINOR 版本中,已移除了该包含类型或命名空间。这在替换QML类型的实现时特别有用。 如果同一QML名称下的其他类型或命名空间中存在相应的QML_ADDED_IN_VERSION(),则在导入低于MAJORMINOR 的模块版本时,将使用已移除的类型;而在导入大于或等于MAJORMINOR 的模块版本时,将使用新增的类型。

QML_REMOVED_IN_VERSION() 仅在 QML 中存在类型或命名空间时才生效,即通过QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_ANONYMOUS 或QML_INTERFACE 宏来实现。

另请参阅 QML_ELEMENT 和QML_NAMED_ELEMENT 。

QML_SEQUENTIAL_CONTAINER(VALUE_TYPE)

该宏将包含或被引用的类型声明为一个顺序容器,用于管理一组VALUE_TYPE 元素。VALUE_TYPE 可以是实际的值类型,也可以是对象类型的指针。由于容器通常是模板,因此您很少能将此宏添加到实际的容器声明中。 应使用 `QML_FOREIGN ` 将类型注册与模板实例化关联起来。利用此方法,例如可以像这样声明顺序容器:

class IntDequeRegistration
{
  Q_GADGET
  QML_FOREIGN(std::deque<int>)
  QML_ANONYMOUS
  QML_SEQUENTIAL_CONTAINER(int)
};

之后,您就可以在 QML 中像使用 JavaScript 数组一样使用该容器了。

class Maze
{
  Q_OBJECT
  Q_ELEMENT
  // 0: North, 1: East, 2: South, 3: West
  Q_PROPERTY(std::deque<int> solution READ solution CONSTANT FINAL)
  [...]
}
Item {
  Maze {
    id: maze
  }

  function showSolution() {
      maze.solution.forEach([...])
  }
}

注意:对于 QML 值类型, QList 会自动注册为顺序容器;对于QML 对象类型, QQmlListProperty 会自动注册。您无需添加这些注册。

注意: 目前无法为 容器指定 自定义名称。传递给QML_NAMED_ELEMENT 的任何参数都会被忽略。自动注册的顺序容器可通过熟悉的list<...>名称访问,例如list<QtObject>或list<font>。

注意:类名 必须是完全限定的,即使你已经处于该命名空间内也是如此。

另请参阅 QML_ANONYMOUS 和QML_FOREIGN()。

QML_SINGLETON

在 QML 中将外围类型声明为单例。此声明仅在该类型为Q_OBJECT 且在 QML 中可用(即具有QML_ELEMENT 或QML_NAMED_ELEMENT() 宏)时生效。 除非该类型通过QML_UNCREATABLE()宏被显式标记为不可创建,否则每次首次访问该类型时,每个QQmlEngine 都会尝试使用该类型的默认构造函数,或签名T *create(QQmlEngine *, QJSEngine *) 的静态工厂函数来创建单例实例。如果两者均存在且可访问,则优先使用默认构造函数。

如果不存在默认构造函数和工厂函数,且未通过QQmlEngine::setExternalSingletonInstance 显式地在引擎上设置实例,则无法访问该单例。如果 QML 引擎实例化了该单例,引擎通常会拥有该单例的所有权,并在引擎自身销毁时将其删除。 相比之下,除非明确指示,否则引擎不会接管外部单例的所有权。您可以通过在单例上调用 `QJSEngine::setObjectOwnership()` 来控制此行为,从而明确指定预期行为。

要将一个可默认构造的类声明为单例,只需添加QML_SINGLETON:

class MySingleton : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    // Q_PROPERTY( ... )
public:
    // members, Q_INVOKABLE functions, etc.
};

如果单例类无法通过默认构造函数初始化,但您可以对其进行修改,则可以为其添加一个工厂函数,以便使其可访问:

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
};

若希望向引擎提供实例,而非让引擎在需要时自行实例化,可使用QML_UNCREATABLE()宏。在这种情况下,该类型无需支持默认构造函数,也不需要工厂函数:

class MySingleton : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    QML_UNCREATABLE("Provided by C++")
    // Q_PROPERTY( ... )
public:
    MySingleton(BackendObject* backend, QObject* parent);

    // members, Q_INVOKABLE functions, etc
};

这要求在首次从 QML 访问该单例之前,通过 `QQmlEngine::setExternalSingletonInstance() ` 将 `MySingleton ` 的实例设置到引擎上。这取代了 `qmlRegisterSingletonInstance ` 函数。

如果您无法修改该类,且该类既没有默认构造函数也没有合适的工厂函数,则可以提供一个 `QML_FOREIGN ` 包装器来定义工厂函数:

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;
    }
};

使用QML_FOREIGN 方法声明无法修改的单例时,也可与QML_UNCREATABLE() 结合使用。此时无需工厂函数,但与之前一样,必须在首次使用前将实例设置到引擎上:

struct SingletonForeign
{
    Q_GADGET
    QML_FOREIGN(MySingleton)
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
    QML_UNCREATABLE("Provided from C++")
};

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT()、qmlRegisterSingletonInstance()、QQmlEngine::singletonInstance()、QQmlEngine::setExternalSingletonInstance() 以及QML 中的单例模式。

[since 6.5] QML_STRUCTURED_VALUE

将周围的值类型标记为结构化类型。结构化值类型可以且最好是从 JavaScript 对象中按属性逐一构建的。不过,结构化值类型也总是QML_CONSTRUCTIBLE_VALUE 。这意味着,你仍然可以提供Q_INVOKABLE 构造函数,以便处理从原始类型进行的构造。

你可以按以下方式声明一个结构化值类型:

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)

    // ...
};

然后,您可以按以下方式为该类型的属性赋值:

QtObject {
    property myValueType v: ({d: 4.4, e: "a string"})
}

额外的圆括号是必要的,用于将 JavaScript 对象与可能被解释为 JavaScript 代码块的内容区分开来。

你还可以通过以下方式构建值列表:

QtObject {
    property list<myValueType> v: [
        {d: 4.4, e: "a string"},
        {d: 7.1, e: "another string"}
    ]
}

该宏在 Qt 6.5 中引入。

另请参阅 QML_VALUE_TYPE 和QML_CONSTRUCTIBLE_VALUE 。

QML_UNAVAILABLE

该宏声明其所包含的类型在 QML 中不可用。它将一个名为QQmlTypeNotAvailable 的内部虚拟类型注册为QML_FOREIGN() 类型,并使用您指定的任何其他 QML 宏。

通常,模块导出的类型应保持固定。但是,如果某个 C++ 类型不可用,您至少应“预留”该 QML 类型名称,并向使用该不可用类型的用户提供有意义的错误信息。

示例:

#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

这将导致任何尝试使用“Game”类型的 QML 代码输出错误消息:

fun.qml: Get back to work, slacker!
   Game {
   ^

使用此方法,您只需一个Q_GADGET 结构体即可自定义错误消息,而无需完整的QObject 。即使不使用QML_UNCREATABLE(),QML_UNAVAILABLE仍会生成比针对完全未知类型的常规“不是类型”错误消息更具体的错误信息。

注意:类名 必须是完全限定的,即使你已经处于该命名空间内也是如此。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT()、QML_UNCREATABLE() 以及QML_FOREIGN()。

QML_UNCREATABLE(reason)

声明该外围类型不得通过 QML 创建。如果该类型在 QML 中可用(即具有QML_ELEMENT 或QML_NAMED_ELEMENT() 宏),则此声明生效。若检测到试图通过 QML 创建该类型,系统将输出错误消息reason 。

某些 QML 类型默认不可创建,特别是通过QML_ANONYMOUS 暴露的类型,以及通过QML_ELEMENT 或QML_NAMED_ELEMENT() 暴露的命名空间。

如果该类型是通过QML_SINGLETON 声明的单例,则添加 QML_UNCREATABLE 表示承诺将通过QQmlEngine::setExternalSingletonInstance 显式地在引擎上设置该类型的实例。

从 Qt 6.0 开始,您可以使用 "" 代替理由,以改用标准消息。

另请参阅 QML_ELEMENT 、QML_NAMED_ELEMENT() 和QML_ANONYMOUS 。

QML_VALUE_TYPE(name)

声明在 QML 中可使用该外围类型或命名空间,并使用name 作为名称。该类型必须是值类型,且名称必须为小写。

class MyValueType
{
    Q_GADGET
    QML_VALUE_TYPE(myValueType)

    // ...
};

另请参阅 《选择 C++ 与 QML 之间的正确集成方法》和《QML_NAMED_ELEMENT 》。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.