编写QML模块

Writing QML Modules

编写QML模块

You can declare a QML module using the CMake QML Module API to:

​您可以使用CMake QML模块API声明QML模块,如下所示:

  • Generate qmldir and *.qmltypes files.
  • ​生成qmldir和*.qmltypes文件。
  • Register C++ types annotated with QML_ELEMENT.
  • ​用QML_ELEMENT注册C++类型。
  • Invoke qmlcachegen.
  • 调用qmlcachegen。
  • Provide modules both in the physical and in resource file system.
  • ​在物理文件系统和资源文件系统中提供模块。
  • Use the pre-compiled versions of QML files.
  • 使用QML文件的预编译版本。
  • Bundle the module's files in the resource file system.
  • 将模块的文件捆绑到资源文件系统中。
  • Combine QML files and C++-based types in the same module.
  • 在同一模块中组合QML文件和基于C++的类型。
  • Create a backing library and an optional plugin. Link the backing library into the application to avoid loading the plugin at run time.
  • 创建备份库和可选插件。将备份库链接到应用程序中,以避免在运行时加载插件。

All the above actions can also be configured separately. For more information, see CMake QML Module API.

​也可以单独配置上述所有操作。有关更多信息,请参阅CMake QML模块API。

Multiple QML Modules in One Binary

一个二进制文件中有多个QML模块

You can add multiple QML modules into the same binary. Define a CMake target for each module and then link the targets to the executable. If the extra targets are all static libraries, the result will be one binary, which contains multiple QML modules. In short you can create an application like this:

您可以将多个QML模块添加到同一个二进制文件中。为每个模块定义一个CMake目标,然后将目标链接到可执行文件。如果额外的目标都是静态库,则结果将是一个二进制文件,其中包含多个QML模块。简而言之,您可以创建如下应用程序:

myProject
    | - CMakeLists.txt
    | - main.cpp
    | - main.qml
    | - onething.h
    | - onething.cpp
    | - ExtraModule
        | - CMakeLists.txt
        | - Extra.qml
        | - extrathing.h
        | - extrathing.cpp

To begin, let's assume main.qml contains an instantiation of Extra.qml:

首先,让我们假设main.qml包含Extra的实例化:

import ExtraModule
Extra { ... }

The extra module has to be a static library so that you can link it into the main program. Therefore, state as much in ExtraModule/CMakeLists.txt:

额外模块必须是一个静态库,以便您可以将其链接到主程序中。因此,请在ExtraModule/CmakeList.txt中尽可能多地说明:

qt_add_library(extra_module STATIC)
qt_add_qml_module(extra_module
    URI "ExtraModule"
    VERSION 1.0
    QML_FILES
        Extra.qml
    SOURCES
        extrathing.cpp extrathing.h
)

This generates two targets: extra_module for the backing library, and extra_moduleplugin for the plugin. Being a static library too, the plugin cannot be loaded at runtime.

这将生成两个目标:支持库的extra_module和插件的extra_moduleplugin。由于也是静态库,插件无法在运行时加载。

In myProject/CMakeLists.txt you need to specify the QML module that main.qml and any types declared in onething.h are part of:

在myProject/CMakeLists.txt中,您需要指定main.qml的QML模块和onething.h中声明的任何类型:

qt_add_executable(main_program main.cpp)

qt_add_qml_module(main_program
    VERSION 1.0
    URI myProject
    QML_FILES
        main.qml
    SOURCES
        onething.cpp onething.h

)

From there, you add the subdirectory for the extra module:

从那里,您可以添加额外模块的子目录:

add_subdirectory(ExtraModule)

To ensure that linking the extra module works correctly, you need to:

为确保链接额外模块正常工作,您需要:

  • Define a symbol in the extra module.
  • 在额外模块中定义符号。
  • Create a reference to the symbol from the main program.
  • 从主程序创建对符号的引用。

QML plugins contain a symbol you can use for this purpose. You can use the Q_IMPORT_QML_PLUGIN macro to create a reference to this symbol. Add the following code to the main.cpp:

​QML插件包含可用于此目的的符号。您可以使用Q_IMPORT_QML_PLUGIN宏创建对此符号的引用。将以下代码添加到main.cpp:

#include <QtQml/qqmlextensionplugin.h>
Q_IMPORT_QML_PLUGIN(ExtraModulePlugin)

ExtraModulePlugin is the name of the generated plugin class. It's composed of the module URI with Plugin appended to it. Then, in the main program's CMakeLists.txt, link the plugin, not the backing library, into the main program:

ExtraModulePlugin是生成的插件类的名称。它由附加了插件的模块URI组成。然后,在主程序的CMakeLists.txt中,将插件链接到主程序中,而不是备份库:

target_link_libraries(main_program PRIVATE extra_moduleplugin)

Exporting Multiple Major Versions from The Same Module

从同一模块导出多个主要版本

qt_add_qml_module by default considers the major version given in its URI argument, even if the individual types declare other versions in their added specific version via QT_QML_SOURCE_VERSIONS or Q_REVISION. If a module is available under more than one version, you also need to decide what versions the individual QML files are available under. To declare further major versions, you can use the PAST_MAJOR_VERSIONS option to qt_add_qml_module as well as the QT_QML_SOURCE_VERSIONS property on individual QML files.

默认情况下,qt_add_qml_module考虑其URI参数中给定的主版本,即使各个类型通过QT_QML_SOURCE_VERSIONS或Q_REVISION在其添加的特定版本中声明其他版本。如果模块在多个版本下可用,则还需要确定各个QML文件在哪个版本下可用。要声明更多的主要版本,可以使用“PAST_MAJOR_VERSIONS”选项到qt_add_qml_module模块,或单个qml文件的QT_QML_SOURCE_VERSIONS属性。

set_source_files_properties(Thing.qml
    PROPERTIES
        QT_QML_SOURCE_VERSIONS "1.4;2.0;3.0"
)

set_source_files_properties(OtherThing.qml
    PROPERTIES
        QT_QML_SOURCE_VERSIONS "2.2;3.0"
)

qt_add_qml_module(my_module
    URI MyModule
    VERSION 3.2
    PAST_MAJOR_VERSIONS
        1 2
    QML_FILES
        Thing.qml
        OtherThing.qml
        OneMoreThing.qml
    SOURCES
        everything.cpp everything.h
)

MyModule is available in major versions 1, 2, and 3. The maximum version available is 3.2. You can import any version 1.x or 2.x with a positive x. For Thing.qml and OtherThing.qml we have added explicit version information. Thing.qml is available from version 1.4, and OtherThing.qml is available from version 2.2. You have to specify the later versions, too, in each set_source_files_properties() because you may remove QML files from a module when bumping the major version. There is no explicit version information for OneMoreThing.qml. This means that OneMoreThing.qml is available in all major versions, from minor version 0.

MyModule有主要版本1、2和3。可用的最大版本为3.2。您可以导入任何版本1.x或2.x(正数x)。表示Thing.qml和OtherThing.qml我们添加了明确的版本信息。Thing.qml可用版本从1.4开始,OtherThing.qml可用版本从2.2开始。您还必须在每个set_source_files_properties()中指定更高版本,因为在更新主版本时,可能会从模块中删除QML文件。OneMoreThing.qml没有明确的版本信息。这意味着OneMoreThing.qml在所有主要版本中都可用,次要版本从0开始。

With this setup, the generated registration code will register the module versionsqmlRegisterModule() for each of the major versions. This way, all versions can be imported.

通过此设置,生成的注册代码将为每个主要版本注册模块versionsqmlRegisterModule()。这样,可以导入所有版本。

Custom Directory Layouts

自定义目录布局

The easiest way to structure QML modules is to keep them in directories named by their URIs. For example, a module My.Extra.Module would live in a directory My/Extra/Module relative to the application that uses it. This way, they can easily be found at run time and by any tools.

构造QML模块的最简单方法是将它们保存在由URI命名的目录中。例如,模块My.Extra.Module将位于相对于使用它的应用程序的目录My/Extra/Module中。这样,在运行时和任何工具都可以轻松找到它们。

In more complex projects, this convention can be too limiting. You might for instance want to group all QML modules in one place to avoid polluting the project's root directory. Or you want to reuse a single module in multiple applications. For those cases, QT_QML_OUTPUT_DIRECTORY in combination with RESOURCE_PREFIX and IMPORT_PATH can be used.

​在更复杂的项目中,此约定可能过于局限。例如,您可能希望将所有QML模块分组在一个地方,以避免污染项目的根目录。或者,您希望在多个应用程序中重用单个模块。对于这些情况,可以使用QT_QML_OUTPUT_DIRECTORY以及RESOURCE_PREFIX和IMPORT_PATH。

To collect QML modules into a specific output directory, for example a subdirectory "qml" in the build directory QT_QML_OUTPUT_DIRECTORY, set the following in the top-level CMakeLists.txt:

​要将QML模块收集到特定的输出目录中,例如构建目录QT_QML_OUTPUT_DIRECTORY中的子目录“qml”,请在顶级CmakeList.txt文件中设置以下内容:

set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)

The output directories of QML modules move to the new location. Likewise, the qmllint and qmlcachegen invocations are automatically adapted to use the new output directory as an import path. Because the new output directory is not part of the default QML import path, you have to add it explicitly at run time, so that the QML modules can be found.

​QML模块的输出目录将移动到新位置。同样,qmlint和qmlcachegen调用也会自动调整,以使用新的输出目录作为导入路径。由于新输出目录不是默认QML导入路径的一部分,因此必须在运行时显式添加它,以便可以找到QML模块。

Now that the physical file system is taken care of, you may still want to move the QML modules into a different place in the resource file system. This is what the RESOURCE_PREFIX option is for. You have to specify it separately in each qt_add_qml_module. The QML module will then be placed under the specified prefix, with a target path generated from the URI appended. For example, consider the following module:

​现在物理文件系统已经处理完毕,您可能仍然希望将QML模块移动到资源文件系统中的其他位置。这就是RESOURCE_PREFIX选项的作用。您必须在每个qt_add_qml_module中单独指定它。然后将QML模块放置在指定的前缀下,并附加从URI生成的目标路径。例如,考虑以下模块:

qt_add_qml_module(
    URI My.Great.Module
    VERSION 1.0
    RESOURCE_PREFIX /example.com/qml
    QML_FILES
        A.qml
        B.qml
)

This will add a directory example.com/qml/My/Great/Module to the resource file system and place the QML module defined above in it. You don't strictly need to add the resource prefix to the QML import path as the module can still be found in the physical file system. However, it generally is a good idea to add the resource prefix to the QML import path because loading from the resource file system is faster than loading from the physical file system for most modules.

这将添加一个目录example.com/qml/My/Great/Module,并将上面定义的qml模块放在其中。您不需要严格地将资源前缀添加到QML导入路径,因为该模块仍然可以在物理文件系统中找到。但是,通常最好将资源前缀添加到QML导入路径,因为对于大多数模块来说,从资源文件系统加载要比从物理文件系统加载快。

If the QML modules are meant to be used in a larger project with multiple import paths, you'll have to do an additional step: Even if you add the import paths at run time, tooling like qmllint does not have access to it, and might fail to find the correct dependencies. Use IMPORT_PATH to tell tooling about the additional paths it has to consider. For example:

如果打算在具有多个导入路径的大型项目中使用QML模块,则必须执行另一个步骤:即使在运行时添加导入路径,像qmllint这样的工具也无法访问它,并且可能无法找到正确的依赖项。使用IMPORT_PATH告诉工具它必须考虑的其他路径。例如:

qt_add_qml_module(
    URI My.Dependent.Module
    VERSION 1.0
    QML_FILES
        C.qml
    IMPORT_PATH "/some/where/else"
)

Eliminating Run Time File System Access

消除运行时文件系统访问

If all QML modules are always loaded from the resource file system, you can deploy the application as a single binary. Let's first consider the simple case:

如果始终从资源文件系统加载所有QML模块,则可以将应用程序作为单个二进制文件进行部署。让我们首先考虑一个简单的情况:

QQmlEngine qmlEngine;
qmlEngine.addImportPath(QStringLiteral(":/"));
// Use qmlEngine to load the main.qml file.

Note: ":/" is used for simplicity here. See Custom Directory Layouts for more complex cases.

​注意:此处使用“:/”是为了简单起见。有关更复杂的情况,请参见自定义目录布局。

If all the modules are linked into the application and if you're following the default resource directory structure, do not add any further import paths as those might override the one you added.

如果所有模块都链接到应用程序中,并且您遵循默认的资源目录结构,则不要添加任何其他导入路径,因为这些路径可能会覆盖您添加的路径。

If you have specified a custom RESOURCE_PREFIX, you have to add the custom resource prefix to the import path instead. You can also add multiple resource prefixes.

如果指定了自定义RESOURCE_PREFIX,则必须将自定义资源前缀添加到导入路径。您还可以添加多个资源前缀。

The path :/qt-project.org/imports/ is part of the default QML import path. If you use it, you don't have to specially add it. Qt's own QML modules are placed there, though. You have to be careful not to overwrite them. For modules that are heavily re-used across different projects :/qt-project.org/imports/ is acceptable. By using it you can avoid forcing all the users to add custom import paths.

路径:/qt-project.org/imports/是默认QML导入路径的一部分。如果你使用它,你不必特别添加它。不过,Qt自己的QML模块放在那里。您必须小心不要覆盖它们。对于在不同项目中大量重复使用的模块:/qt-project.org/imports/可接受。使用它可以避免强制所有用户添加自定义导入路径。

Integrating custom QML plugins

集成定制QML插件

If you bundle an image provider in the QML module, you need to implement the QQmlEngineExtensionPlugin::initializeEngine() method. This, in turn, makes it necessary to write the own plugin. To support this use case, NO_GENERATE_PLUGIN_SOURCE can be used.

​如果在QML模块中绑定了图像提供者,则需要实现QQmlEngineExtensionPlugin::initializeEngine()方法。反过来,这就需要编写自己的插件。为了支持此用例,可以使用NO_GENERATE_PLUGIN_SOURCE。

Let's consider a module that provides its own plugin source:

让我们考虑一个提供自己插件源的模块:

qt_add_qml_module(imageproviderplugin
    VERSION 1.0
    URI "ImageProvider"
    PLUGIN_TARGET imageproviderplugin
    NO_PLUGIN_OPTIONAL
    NO_GENERATE_PLUGIN_SOURCE
    CLASS_NAME ImageProviderExtensionPlugin
    QML_FILES
        AAA.qml
        BBB.qml
    SOURCES
        moretypes.cpp moretypes.h
        myimageprovider.cpp myimageprovider.h
        plugin.cpp
)

You may declare an image provider in myimageprovider.h, like this:

您可以在myimageprovider.h中声明图像提供者,像这样:

class MyImageProvider : public QQuickImageProvider
{
    [...]
};

In plugin.cpp you can then define the QQmlEngineExtensionPlugin:

​在plugin.cpp中,可以定义QQmlEngineExtensionPlugin:

#include <myimageprovider.h>
#include <QtQml/qqmlextensionplugin.h>

class ImageProviderExtensionPlugin : public QQmlEngineExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
public:
    void initializeEngine(QQmlEngine *engine, const char *uri) final
    {
        Q_UNUSED(uri);
        engine->addImageProvider("myimg", new MyImageProvider);
    }
};

This will make the image provider available. The plugin and the backing library both are in the same CMake target imageproviderplugin. This is done so that the linker does not drop parts of the module in various scenarios.

这将使图像提供者可用。插件和备份库都位于同一个CMake目标imageproviderplugin中。这样做是为了链接器不会在各种情况下删除模块的部分。

As the plugin creates an image provider, it no longer has a trivial initializeEngine function. Therefore, the plugin is no longer optional.

当插件创建图像提供者时,它不再具有简单的initializeEngine函数。因此,插件不再是可选的。

© 2022 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.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值