Qt Interface Framework Generator Climate Example

This Example shows how to use the Qt Interface Framework Generator.

Introduction

This example shows you how you can use the Qt Interface Framework Generator to build a new component. Based on a single QFace Interface Definition Language (IDL) file, the example generates:

  • a shared library with the front-end code
  • a back-end simulator plugin

The IDL File

The IDL file used in this example represents a simplified climate control interface that contains a single interface and some enumerated types.

Let's take a look at a minimal version of the same QFace IDL file:

module Example.If.ClimateModule 1.0;

interface ClimateControl {
    bool airConditioning;
    int fanSpeedLevel;
    readonly int outsideTemperature;
    RecirculationMode recirculationMode;
}

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

First, we need to define which module we want to describe. The module acts as a namespace, because the IDL file can contain multiple interfaces.

module Example.If.Climate 1.0;

The most important part of the module is its interface definition.

interface ClimateControl {
    bool airConditioning;
    int fanSpeedLevel;
    readonly int outsideTemperature;
    RecirculationMode recirculationMode;
}

In this case, we define an interface named ClimateControl consisting of a few properties it should offer. Each property definition must contain at least a type and a name. Most of the basic types are built-in and can be found in the QFace IDL syntax. Each property can also be set to be readonly, as seen in the outsideTemperature property. The last property is special as it uses a custom type, that is defined after the interface definition.

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

It defines an enumeration with all the values it supports, including the numeric value of each individual item.

Comments and Annotations

Compared to the minimal IDL we saw in the previous section, the full IDL file contains a lot of comments and annotations.

Comments starting with /** define documentation statements and can be converted into documentation markup like QDoc or Doxygen, by the generation template.

Annotations

Annotations are used to add additional information to the IDL statements. They are YAML fragments that provide a key-value store. The generation template defines the supported annotations.

Here's an overview of all the annotations used in this example and what they do:

AnnotationDescription
@config: {zoned: true}
Specifies that the interface supports different zones.
@config_simulator: { range:[0, 5] }
Specifies a range of valid values for numerical properties.

Note: The range annotation used here is a shortcut to specify both minimum and maximum values.

In addition to the IDL file, a YAML file with the same base name is used to add extra configurations. These configurations may also be added directly into the IDL file, but we choose to keep them separate for readability.

Some of these extra configurations are highlighted below:

Example.If.Climate.ClimateControl:
    config_simulator:
        zones: { left : FrontLeft, right : FrontRight, rear: Rear }
Defines the names for the supported zones.
Example.If.ClimateModule.ClimateControl#fanSpeedLevel:
    config_simulator:
        default:
            FrontLeft: 2
            FrontRight: 5
Specifies the default value assigned to a property in the simulator back-end plugin. Each zone can have a different default value.

Front End Library

Now we want to use the Interface Framework Generator to generate a QML module that contains a C++ implementation of our IDL file.

In this case, we use the frontend template, that generates a class derived from QIfAbstractZonedFeature including all the specified properties. The generated library uses the Dynamic Backend System from QtInterfaceFramework, providing an easy way to change the behavior implementations. For more details, see Back End Simulator Plugin.

To let the autogenerator create a QML module, it needs to be integrated into the build system.

qt_ifcodegen_add_qml_module(climate_frontend
    IDL_FILES example-climate.qface
    TEMPLATE frontend
)

Similar to qt_add_qml_module the call of qt_ifcodegen_add_qml_module makes sure that the generated code can be used from QML. The uri and version is defined by the module statement in the IDL file:

module Example.If.ClimateModule 1.0;

Back End Simulator Plugin

Since the front-end library uses the Dynamic Backend System, we need a corresponding back-end plugin, for the library to provide some functionality. To generate a mock version of the back-end plugin called "Simulator Backend", you can use the backend_simulator template from the same IDL file as the front-end library. The build system integration works in the similar way, but it uses a different generation template.

A plugin is defined and extended by calling the codegenerator, this time with the backend_simulator template:

qt_ifcodegen_add_plugin(climate_backend_simulator
    IDL_FILES example-climate.qface
    TEMPLATE backend_simulator
)

For the plugin to compile correctly it needs to get the backend interface header from the previously created library. However, this header is not part of our source tree but the build tree, because it is also generated. We provide this header by adding it to the include path using the following code:

target_link_libraries(climate_backend_simulator PRIVATE
    climate_frontend
)

The backend_simulator template makes use of the @config_simulator annotations explained above. This means that the generated back end provides the default values defined in the annotations and checks the boundaries of new values using the minimum/maximum or range annotations.

Using the zones annotations, the generated back end provides individual values for every zone and communicates the available zones to the front-end library.

Demo Application

The demo application presents a simple QML climate ui which uses the properties of our auto generated interface.

Since we set the zoned annotation and also provided the available zones for the simulation-backend, we can now access the different zones in the QML code. The following code snippet shows how to the targetTemperature for the zone FrontLeft is accessed:

TempControl {
    value: climateCtrl.zoneAt.FrontLeft.targetTemperature
    onValueModified: {
        climateCtrl.zoneAt.FrontLeft.targetTemperature = value
    }
}

Properties which are not zoned can be accessed directly:

Button {
    Layout.leftMargin: 5
    Layout.rightMargin: 5
    Layout.maximumWidth: 50
    text: "A/C"
    checkable: true
    checked: climateCtrl.airConditioning
    onToggled: {
        climateCtrl.airConditioning = checked
    }
}

Our application doesn't know about our back-end plugin, so, we need to put this plugin in the folder where our application looks for plugins. By default, Qt looks in the plugins folder within its installation directory or in the application's current working directory. For QtInterfaceFramework plugins to be found, they need to be placed within a interfaceframework sub-folder.

To make sure this is done automatically, we add the following line to the build system file:

set_target_properties(climate_backend_simulator PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY interfaceframework
)

Example project @ code.qt.io

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