Qt IVI 生成器气候示例

本示例展示了如何使用Qt IVI生成器。

简介

本示例向您展示如何使用Qt IVI生成器构建新组件。基于单个QFace IDL文件,本示例生成了

  • 一个包含前端代码的共享库
  • 一个后端模拟插件
  • 一个演示应用,它显示当前模块中的值

IDL文件

本示例中使用的IDL文件表示一个简化的气候控制接口,它包含一个接口和一些枚举类型。

让我们看看相同的QFace IDL文件的最小版本

module Example.IVI.Climate 1.0;

interface ClimateControl {
    bool airConditioning;
    int fanSpeedLevel;
    RecirculationMode recirculationMode;
    AirflowDirection airflowDirections;
}

enum RecirculationMode {
    RecirculationOff = 0x0,
    RecirculationOn = 0x1,
    AutoRecirculation = 0x2
}

flag AirflowDirection {
    Windshield = 1,
    Dashboard = 2,
    Floor = 4
}
演练

首先,我们需要定义我们想要描述的哪个module。该module作为命名空间,因为IDL文件可以包含多个接口。

module Example.IVI.Climate 1.0;

module最重要的部分是它的interface定义。

interface ClimateControl {
    bool airConditioning;
    int fanSpeedLevel;
    RecirculationMode recirculationMode;
    AirflowDirection airflowDirections;
}

在这种情况下,我们定义了一个名为ClimateControlinterface,它包含了一些它应提供的属性。每个属性定义必须包含至少一个类型和一个名称。大多数基本类型是内置的,可以在QFace IDL语法中找到。最后两个属性是特殊的,因为它们使用自定义类型,这些类型是在interface定义之后定义的。

enum RecirculationMode {
    RecirculationOff = 0x0,
    RecirculationOn = 0x1,
    AutoRecirculation = 0x2
}

flag AirflowDirection {
    Windshield = 1,
    Dashboard = 2,
    Floor = 4
}

第一个定义是一个包含所有支持值的enum,包括每个单独项目的数值。第二个定义类似,但使用flag类型。

注释和注解

与上一节中看到的简洁IDL相比,完整的IDL文件包含了大量的注释和注解。

/**开头的注释定义文档语句,并且可以通过生成模板转换为文档标记,例如QDoc或Doxygen。

注解

注解用于向IDL语句添加附加信息。它们是YAML片段,提供键值存储。生成模板定义了支持的注解。

以下是本示例中使用的所有注解的概述以及它们的功能

注解描述
@config: {zoned: true}
指定接口支持不同的区域。
@config: {qml_type: "UiClimateControl"}
指定从QML使用的组件名称。
@config: {id: "example.qtivi.ClimateControl/1.0"}
指定用于匹配后端插件的ID。
@config_simulator: { range:[0, 50] }
指定数值属性的合理值范围。

注意:此处使用的range注解是指定最小值和最大值的快捷方式。

@config_simulator: { minimum: 0; maximum: 50 }
指定数值属性的最低值和最高值。
@config_simulator: { domain: ["cold", "mild", "warm" ] }
指定属性的合理值列表。
@config: {interfaceBuilder: "echoInterfaceBuilder"}
指定插件应使用自定义函数生成后端实例。

除了IDL文件外,还会使用具有相同基本名称的YAML文件来添加额外的配置。这些配置也可以直接添加到IDL文件中,但为了可读性,我们选择将其保持分开。

以下是一些额外配置的示例。

Example.IVI.Climate.ClimateControl:
    config_simulator:
        zones: { left : FrontLeft, right : FrontRight, rear: Rear }
定义了受支持区域的名。
Example.IVI.Climate.ClimateControl#recirculationMode:
    config_simulator:
        default: RecirculationMode.RecirculationOff
指定了模拟器后端插件中属性分配的默认值。

前端库

现在我们想使用IVI生成器来生成包含我们模块及其接口的C++实现的共享库。

在这种情况下,我们使用frontend模板,该模板生成一个从QIviAbstractZonedFeature派生的类,包括所有指定的属性。生成的库使用来自动态后端系统QtIviCore,提供了一种轻松更改行为实现的方法。更多详细信息,请参阅后端模拟插件

要调用用于我们的共享库的自动生成器,qmake项目文件需要使用ivigenerator qmake功能。下面的片段显示了如何这样做

CONFIG += ivigenerator
QFACE_SOURCES = ../example-ivi-climate.qface

通过将ivigenerator添加到CONFIG变量中,将加载并解析ivigenerator功能文件中的QFACE_SOURCES变量,就像在正常的qmake项目中处理SOURCES变量一样。

然而,使用CONFIG变量激活qmake功能有一个缺点:如果此功能不可用,则不会报告任何错误。但是,您可以使用以下附加代码来报告错误

QT_FOR_CONFIG += ivicore
!qtConfig(ivigenerator): error("No ivigenerator available")

项目文件的其他部分是一个普通的库设置,应在Linux、macOS和Windows上正常工作。

后端模拟插件

由于frontend库使用动态后端系统,我们需要相应的backend插件,以便库提供某些功能。为了生成名为“模拟器后端”的备份插件,您可以使用与frontend库相同的IDL文件中的backend_simulator模板。qmake集成方式相同,但它使用QFACE_FORMAT变量来告诉ivigenerator使用不同的生成模板。

CONFIG += ivigenerator plugin
QFACE_FORMAT = backend_simulator
QFACE_SOURCES = ../example-ivi-climate.qface
PLUGIN_TYPE = qtivi
PLUGIN_CLASS_NAME = ClimateSimulatorPlugin

由于我们想生成一个插件而不是普通的库,我们通过将plugin添加到CONFIG变量中来指示qmake这样做。为了正确编译插件,它需要从前创建的库中获取后端接口头文件。然而,此头文件不是我们的源代码树的一部分,而是构建树的一部分,因为它也会被生成。我们通过以下结构将其添加到包含路径中

INCLUDEPATH += $$OUT_PWD/../frontend

backend_simulator模板利用了之前所解释的@config_simulator注释。这意味着生成的后端提供了注释中定义的默认值,并使用minimum/maximumrange注释来检查新值的界限。

使用zones注释,生成的后端提供了每个区域的单个值,并将可用的区域与前端库通信。更多信息,请参阅气候控制系统QML示例

演示应用程序

演示应用程序提供了一个简单的QML界面,其中包括生成的界面的所有属性。

由于我们没有提供QML插件,因此该应用程序需要链接到生成的 frontend 库,并调用模块单例中生成的ClimateModule::registerTypesClimateModule::registerQmlTypes方法,这些方法将所有自动生成的接口和类型注册到QML引擎中。

在我们的QML应用程序中,我们仍然需要使用与IDL文件中相同的模块URI来导入模块。之后,该接口可以像常规的QML项目一样实例化。

import Example.IVI.Climate 1.0

Window {

    visible: true
    width: 640
    height: 480
    title: qsTr("QtIVI Climate")

    UiClimateControl {
        id: climateCtrl
    }

    Column {
        anchors.fill: parent
        anchors.margins: 5

        Text {
            text: "Air Conditioning: " + climateCtrl.airConditioning
        }
...

我们的应用程序不了解我们的后端插件,因此,我们需要将此插件放置在我们的应用程序查找插件的目标文件夹中。默认情况下,Qt在其安装目录的plugins文件夹或应用程序当前工作目录中查找。要找到QtIvi插件,它们需要被放置在qtivi子文件夹中。

为确保此操作自动完成,我们将在我们的后端项目文件中添加以下行

DESTDIR = ../qtivi

示例项目 @ code.qt.io

©2020 Qt公司有限公司版权所有。本文件中包含的文档贡献权归各自的所有者所有。本文件中提供的文档是根据自由软件基金会发布的、经修改的GNU自由文档许可协议版本1.3条款授权的。Qt及其相关标志是芬兰及其它地区的Qt公司的商标。所有其他商标归各自的所有者所有。