QIfSimulationEngine 类

提供从 QML 脚本模拟后端的方式。更多...

头文件 #include <QIfSimulationEngine>
qmakeQT += interfaceframework
继承 QQmlApplicationEngine

公共函数

QIfSimulationEngine(QObject *parent = nullptr)
QIfSimulationEngine(const QString &identifier, QObject *parent = nullptr)
voidloadSimulation(const QUrl &file)
voidloadSimulationData(const QString &dataFile)
voidregisterSimulationInstance(T *instance, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
QVariantqtif_convertFromJSON(const QVariant &value)

QIF_SIMULATION_TRY_CALL(instance_type, function, ret_type, ...)
QIF_SIMULATION_TRY_CALL_FUNC(instance_type, function, ret_func, ...)

详细描述

此类是扩展的 QQmlApplicationEngine,可用来加载 QML 文件。它专门为仿真后端编写从 QML 中的行为脚本而设计。对其功能概述,请参阅Qt 接口框架仿真系统

与世界末日相比,QIfSimulationEngine 提供一个额外的模板函数,称为 registerSimulationInstance()。使用此函数将类实例注册为 QML 类型。在 QML 文件中,此 QML 类型可用于定义函数调用的行为,更新属性或发出信号。

注册实例

您可以通过调用 registerSimulationInstance()将任何从 QObject 派生的类的实例注册到 QIfSimulationEngine。类似于 qmlRegisterTypes,提供的 URI、版本和名称用于从 QML 中导入类型。

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int currentTemperature READ currentTemperature WRITE setCurrentTemperature NOTIFY currentTemperatureChanged)

    ...
}

此简单类的实例可以按以下方式注册

QIfSimulationEngine engine;
MyClass myClass;
engine.registerSimulationInstance<MyClass>(&myClass, "Test", 1, 0, "MyClass");
engine.loadSimulation("simulation.qml")

已注册的实例具有任何暴露给 QML 的 C++ 类相同的约束,并需要使用 Q_PROPERTYQ_INVOKABLE 或槽来使功能可用。

从 QML 使用类型

将实例注册到引擎后,该类型可以像任何其他声明性形式的 QML 元素一样使用。

import QtQuick
import Test

Item {
    MyClass {
        id: myClass

        Component.onCompleted: currentTemperature = 10;
    }

    Timer {
        running: true
        repeat: true
        interval: 1000
        onTriggered: myClass.currentTemperature++;
    }
}

此 QML 文件将 myClasscurrentTemperature 初始化为值 10 并每秒增加。

同样地,可以从 C++ 端更新值,而 QML 端可以响应变化。例如,以下 QML 片段每当 currentTemperature 改变时打印它。

import QtQuick
import Test

MyClass {
    onCurrentTemperatureChanged: print(currentTemperature)
}

myClass 变量更新时,将调用槽。

QIfSimulationEngine engine;
MyClass myClass;
engine.registerSimulationInstance<MyClass>(&myClass, "Test", 1, 0, "MyClass");
engine.loadSimulation("simulation.qml")
...
myClass.setCurrentTemperature(100);

从实例到引擎的前向调用

您还可以为 QML 中的 invokable 函数提供行为,但这需要您扩展公开的类。例如,通过向 setCurrentTemperature 设置器添加以下行

void MyClass::setCurrentTemperature(int currentTemperature)
{
    QIF_SIMULATION_TRY_CALL(MyClass, "setCurrentTemperature", void, currentTemperature);

    if (m_currentTemperature == currentTemperature)
        return;
    m_currentTemperature = currentTemperature;
    emit currentTemperatureChanged(m_currentTemperature);
}

现在调用 setCurrentTemperature() 将尝试将调用转发到 QML 实例,如果 QML 中定义了匹配签名的函数。如果成功,setCurrentTemperature() 将使用其返回值并避免运行原始的 C++ 函数。

使用以下 QML 片段,将跳过 C++ 设置器,并在控制台只发出错误

import QtQuick
import Test

MyClass {
    function setCurrentTemperature(temperature) {
        print("Updating the temperature is not possible")
    }
}

在实例中重用现有行为

用 QML 行为替换 C++ 功能并不总是希望如此。然而,从 QML 也可以调用原始 C++ 行为。在这种情况下,原始 C++ 函数需要是 Q_INVOKABLE 或槽。类似地,这就像 C++ 中的函数重写一样工作,其中可以通过调用 <BaseClass>::<function> 访问被重写函数的功能。在公开的 QML 类型中,这可以通过在 Base 对象中调用函数来实现。

import QtQuick
import Test

MyClass {
    function setCurrentTemperature(temperature) {
        print("Updating the temperature: " + temperature )
        Base.setCurrentTemperature(temperature)
    }
}

以下 QML 片段在 QML 中重写了 setCurrentTemperature() 行为并打印新值的调试消息。使用 Base.setCurrentTemperature(temperature) 调用原始 C++ 行为。

多个 QML 实例

注册的实例作为普通 QML 类型公开。这使得在 QML 中有多个声明成为可能,从而有多个 QML 实例链接到相同的 C++ 实例。所有实例都可以更新和响应属性更改和信号发射,但应谨慎使用,因为这可能导致属性更新循环和其他问题。

将 C++ 函数调用转发到 QML 是有限的。每个调用仅转发到单个 QML 实例,因为返回值来自此调用。如果多个 QML 实例定义了相同的方法,则 C++ 调用始终转发到第一个注册的 QML 实例。

运行时覆盖

每个 QIfSimulationEngine 都可以接受一个额外的标识符,该标识符可以用作在运行时覆盖模拟 QML 文件或模拟数据文件。环境变量需要以下格式

QTIF_SIMULATION_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]
QTIF_SIMULATION_DATA_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]

成员函数文档

[显式] QIfSimulationEngine::QIfSimulationEngine(QObject *parent = nullptr)

使用指定的 parent 构造一个新 QIfSimulationEngine。

[显式] QIfSimulationEngine::QIfSimulationEngine(const QString &identifier, QObject *parent = nullptr)

使用给定的 标识符父对象 创建一个新的 QIfSimulationEngine。

可以使用 标识符 覆盖模拟 QML 文件或模拟数据文件。

另请参阅 运行时和覆盖。

void QIfSimulationEngine::loadSimulation(const QUrl &file)

将 QML 文件 作为模拟行为加载。

除了 QQmlApplicationEngine::load(),此函数还提供以下格式的环境变量来更改使用的主文件的功能

QTIF_SIMULATION_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]

模拟引擎的标识符可以在其构造函数中设置。

void QIfSimulationEngine::loadSimulationData(const QString &dataFile)

加载提供的 dataFile 作为模拟数据文件。

给定的文件必须是 JSON 格式,在传递给 IfSimulator 全球对象进行解析之前,将在这里解析错误。此文件可以在运行时使用以下环境变量进行覆盖

QTIF_SIMULATION_DATA_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]

模拟引擎的标识符可以在其构造函数中设置。

另请参阅IfSimulator

template <typename T> void QIfSimulationEngine::registerSimulationInstance(T *instance, const char *uri, int versionMajor, int versionMinor, const char *qmlName)

qmlName 的名称,在从 uri 导入的库中注册指定的 实例,版本号由 versionMajorversionMinor 组成。

注意:已注册的实例仅适用于此 QIfSimulationEngine 实例。从另一个 QIfSimulationEngineQQmlEngine 中使用它将不起作用并产生错误。

另请参阅qmlRegisterType

相关非成员

QVariant qtif_convertFromJSON(const QVariant &value)

value 从 JSON 转换为有效的 C++ 类型。

提供的 JSON 值需要遵循 IfSimulator 数据格式

宏文档

QIF_SIMULATION_TRY_CALL(instance_type, function, ret_type, ...)

尝试在 QML 已注册的 instance_type 实例中调用 function。可变参数作为参数传递给 QML 中的函数。

如果调用成功,将返回 ret_type 的值,并且在此宏之后的所有代码都将 不会 执行。

另请参阅QIF_SIMULATION_TRY_CALL_FUNC从实例到引擎的转发调用

QIF_SIMULATION_TRY_CALL_FUNC(instance_type, function, ret_func, ...)

尝试在 QML 已注册的 instance_type 实例中调用 function。可变参数作为参数传递给 QML 中的函数。

如果调用成功,通过 ret_func 传递的代码将被执行。这在需要首先转换返回值的情况下很有用。原始返回值作为 return_value 可用。

QIF_SIMULATION_TRY_CALL_FUNC(MyClass, "contactList", return return_value.toStringList());

另请参阅 QIF_SIMULATION_TRY_CALL从实例向引擎转发调用

© 2024 Qt 公司。本文档中的文档贡献包含各自的版权。提供的文档根据自由软件基金会发布的 GNU 自由文档许可协议第 1.3 版 的条款提供许可。Qt 和相应的标志是芬兰及/或其他国家的 Qt 公司的 商标。所有其他商标均属于各自的所有者。