SCXML Media Player

发送数据到 C++ 数据模型和接收数据从 C++ 数据模型。

媒体播放器 demonstrates how to access data from a C++ data model. The data model enables writing C++ code for expr 属性和 <script> 元素。 数据部分 的数据模型后援是子类化的 QScxmlCppDataModel , for which the Qt SCXML compiler ( qscxmlc ) generates the dispatch methods.

UI 是使用 Qt Quick 创建的。

运行范例

要运行范例从 Qt Creator ,打开 Welcome 模式,然后选择范例从 Examples 。更多信息,拜访 构建和运行范例 .

使用 C++ 数据模型

We specify the data model as a value of the datamodel 属性在 <scxml> element in the SCXML file:

<scxml
    xmlns="http://www.w3.org/2005/07/scxml"
    version="1.0"
    name="MediaPlayerStateMachine"
    initial="stopped"
    datamodel="cplusplus:TheDataModel:thedatamodel.h"
					

The format of the datamodel attribute is: cplusplus:<class-name>:<classdef-header> . Therefore, we need a file called thedatamodel.h that contains a subclass of QScxmlCppDataModel :

#include "qscxmlcppdatamodel.h"
#include <QtQml/qqml.h>
class TheDataModel: public QScxmlCppDataModel
{
    Q_OBJECT
    Q_SCXML_DATAMODEL
					

QScxmlCppDataModel 派生自 QObject , so we add the Q_OBJECT macro in the private section of the definition, right after the opening bracket. We then place the Q_SCXML_DATAMODEL macro after Q_OBJECT . The macro expands to the declaration of virtual methods, the implementation of which is generated by the Qt SCXML compiler.

In the SCXML file, we specify C++ statements in the <script> element and use the expr attribute to access the data model:

    <state id="stopped">
        <transition event="tap" cond="isValidMedia()" target="playing"/>
    </state>
    <state id="playing">
        <onentry>
            <script>
                media = eventData().value(QStringLiteral("media")).toString();
            </script>
            <send event="playbackStarted">
                <param name="media" expr="media"/>
            </send>
        </onentry>
        <onexit>
            <send event="playbackStopped">
                <param name="media" expr="media"/>
            </send>
        </onexit>
        <transition event="tap" cond="!isValidMedia() || media == eventData().value(QStringLiteral("media"))" target="stopped"/>
        <transition event="tap" cond="isValidMedia() && media != eventData().value(QStringLiteral("media"))" target="playing"/>
    </state>
					

The Qt SCXML compiler generates the various evaluateTo methods and converts the expressions and scripts into lambdas inside those methods in mediaplayer.cpp :

bool TheDataModel::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
....
    return [this]()->bool{ return isValidMedia(); }();
....
}
QVariant TheDataModel::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
....
        return [this]()->QVariant{ return media; }();
....
}
void TheDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
....
        [this]()->void{ media = eventData().value(QStringLiteral("media")).toString(); }();
....
}
					

范例工程 @ code.qt.io