QIviSimulationEngine 类

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

头文件 #include <QIviSimulationEngine>
qmakeQT += ivicore
继承 QQmlApplicationEngine

公共函数

voidloadSimulation(const QUrl &file)
voidloadSimulationData(const QString &dataFile)
voidregisterSimulationInstance(T *instance, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
QVariantqtivi_convertFromJSON(const QVariant &value)

QIVI_SIMULATION_TRY_CALL(instance_type, function, ret_type, ...)
QIVI_SIMULATION_TRY_CALL_FUNC(instance_type, function, ret_func, ...)

详细描述

此类是扩展的 QQmlApplicationEngine,可用以加载 QML 文件。它专为 模拟后端 脚本其行为而设计。关于其功能概述,请参阅 Qt IVI 模拟系统

与普通的 QQmlEngine 相比,QIviSimulationEngine 提供了一个名为 registerSimulationInstance() 的额外模板函数。使用此函数将类实例注册为 QML 类型。在 QML 文件中,可以使用该类型定义函数调用、更新属性或发出信号的行为。

注册实例

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

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

    ...
}

可以这样注册此类的一个简单实例:

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

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

从 QML 使用类型

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

import QtQuick 2.0
import Test 1.0

Item {
    MyClass {
        id: myClass

        Component.onCompleted: currentTemperature = 10;
    }

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

此 QML 文件使用 10 的值初始化 myClasscurrentTemperature,并每秒增加它:

同样,值可以从C++端更新,QML端可以响应变更。例如,以下QML代码片段在currentTemperature变化时打印它

import QtQuick 2.0
import Test 1.0

MyClass {
    onCurrentTemperatureChanged: print(currentTemperature)
}

myClass变量更新时,将调用槽

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

实例到引擎的转调

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

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

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

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

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

import QtQuick 2.0
import Test 1.0

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 2.0
import Test 1.0

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实例。

运行时覆盖

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

QTIVI_SIMULATION_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]
QTIVI_SIMULATION_DATA_OVERRIDE=<identifier>=<file>[;<identifier>=<file>]

成员函数文档

void QIviSimulationEngine::loadSimulation(const QUrl &file)

将QML file加载为模拟行为。

除了QQmlApplicationEngine::load()之外,该函数还提供通过以下格式的环境变量更改使用的模拟文件的功能

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

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

void QIviSimulationEngine::loadSimulationData(const QString &dataFile)

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

给定的文件必须是JSON格式,并且在此处对其进行错误检查,然后再将其传递给IviSimulator全局对象,以便在QML中访问。可以创建以下环境变量来在运行时覆盖此文件。

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

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

另请参阅IviSimulator

模板 <typename T> void QIviSimulationEngine::registerSimulationInstance(T *instance, const char *uri, int versionMajor, int versionMinor, const char *qmlName)

将指定的instance注册到QML系统中,名称为qmlName,在从uri导入的库中,版本号为versionMajorversionMinor组成。

注意:已注册的实例仅对QIviSimulationEngine实例可用。从另一个QIviSimulationEngineQQmlEngine使用它将不起作用,并产生错误。

另请参阅qmlRegisterType

相关非成员

QVariant qtivi_convertFromJSON(const QVariant &value)

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

提供的JSON值需要遵循IviSimulator Data Format

宏文档

QIVI_SIMULATION_TRY_CALL(instance_type, function, ret_type, ...)

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

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

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

QIVI_SIMULATION_TRY_CALL_FUNC(instance_type, function, ret_func, ...)

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

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

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

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

©2020 The Qt Company Ltd. 本文档中包含的贡献权属于各自的拥有者。本提供的文档根据自由软件基金会发布的GNU自由文档许可证版本1.3的条款进行许可。Qt及其相应商标是芬兰和/或全世界The Qt Company Ltd.的商标。所有其他商标均为其各自所有者的财产。