SCXML Media Player▲
Media Player demonstrates how to access data from a C++ data model. The data model enables writing C++ code for expr attributes and <script> elements. The data part of the data model is backed by a subclass of QScxmlCppDataModel, for which the Qt SCXML compiler (qscxmlc) generates the dispatch methods.
The UI is created using Qt Quick.
Running the Example▲
To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
Using the C++ Data Model▲
We specify the data model as a value of the datamodel attribute of the <scxml> element in the SCXML file:
&
lt;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 derives from 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:
&
lt;state id=
"stopped"
&
gt;
&
lt;transition event=
"tap"
cond=
"isValidMedia()"
target=
"playing"
/&
gt;
&
lt;/
state&
gt;
&
lt;state id=
"playing"
&
gt;
&
lt;onentry&
gt;
&
lt;script&
gt;
media =
eventData().value(QStringLiteral(&
amp;quot;media&
amp;quot;)).toString();
&
lt;/
script&
gt;
&
lt;send event=
"playbackStarted"
&
gt;
&
lt;param name=
"media"
expr=
"media"
/&
gt;
&
lt;/
send&
gt;
&
lt;/
onentry&
gt;
&
lt;onexit&
gt;
&
lt;send event=
"playbackStopped"
&
gt;
&
lt;param name=
"media"
expr=
"media"
/&
gt;
&
lt;/
send&
gt;
&
lt;/
onexit&
gt;
&
lt;transition event=
"tap"
cond=
"!isValidMedia() || media == eventData().value(QStringLiteral(&quot;media&quot;))"
target=
"stopped"
/&
gt;
&
lt;transition event=
"tap"
cond=
"isValidMedia() &amp;&amp; media != eventData().value(QStringLiteral(&quot;media&quot;))"
target=
"playing"
/&
gt;
&
lt;/
state&
gt;
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
]()-&
gt;bool
{
return
isValidMedia(); }
();
....
}
QVariant TheDataModel::
evaluateToVariant(QScxmlExecutableContent::
EvaluatorId id, bool
*
ok) {
....
return
[this
]()-&
gt;QVariant{
return
media; }
();
....
}
void
TheDataModel::
evaluateToVoid(QScxmlExecutableContent::
EvaluatorId id, bool
*
ok) {
....
[this
]()-&
gt;void
{
media =
eventData().value(QStringLiteral("media"
)).toString(); }
();
....
}