The Qt State Machine Framework provides a practical mechanism to implement a GUI application as a state chart. Using Qt 6, this webinar will:
-Provide an intro to the framework
-Explore its features and its API in both C++ and QML
-Illustrate with an example how it can simplify development where the user interface is written in QML
This webinar is for any developer who wants to implement robust user interfaces.
Introduction to the Qt State Machine Framework using Qt 6
1. Integrated Computer Solutions Inc. www.ics.com
An Introduction to the Qt State
Machine Framework using Qt 6
December 16, 2021
Christopher Probst, ICS
1
2. Integrated Computer Solutions Inc. www.ics.com
About ICS
Delivering Smart Devices for a Connected World
● Founded in 1987
● Largest source of independent Qt expertise in North America
● Trusted Qt Service Partner since 2002
● Exclusive Open Enrollment Training Partner in North America
● Provides integrated custom software development and user experience (UX) design
● Embedded, touchscreen, mobile and desktop applications
● HQ in Waltham, MA with offices in California, Canada, Europe
Boston UX
● Part of the ICS family, focusing on UX design
● Designs intuitive touchscreen interfaces for high-impact embedded
and connected medical, industrial and consumer devices
2
3. Integrated Computer Solutions Inc. www.ics.com
● A C++, (and also QML) API that allows to create and execute state graphs
● Not to be confused with the state and transitions from Item in QML
● Based on Harel’s statecharts
● Allows for hierarchical statecharts with superstates
● State Machine is signal and event driven
● https://doc-snapshots.qt.io/qt6-dev/qtstatemachine-index.html
What is the Qt State Machine Framework
3
4. Integrated Computer Solutions Inc. www.ics.com
C++ Type Description
QStateMachine Provides a hierarchical finite state machine
QState Provides a state for the state machine
QHistoryState Provides a means of returning to a previously active sub-state
QFinalState Provides a final state
QSignalTransition Provides a transition based on a Qt signal
QEventTransition Provides an a transition based on a QEvent
Note: To access the API it is necessary to link against the Qt module StateMachine:
C++ Types Available
find_package(Qt6 COMPONENTS StateMachine REQUIRED)
target_link_libraries(mytarget PRIVATE Qt6::StateMachine)
CMakeLists.txt
4
6. Integrated Computer Solutions Inc. www.ics.com
Business Logic/UI Paradigm
-
BusinessLogic
C++
UI in QML
● C++ code “knows” nothing of the implementation details in QML
6
8. Integrated Computer Solutions Inc. www.ics.com
Creating State Machine
8
Just create an instance of a QStateMachine in the business logic...
class ScreenSelector : public QObject
{
Q_OBJECT
Q_PROPERTY(QUrl currentScreen READ currentScreen WRITE setCurrentScreen NOTIFY currentScreenChanged)
public:
explicit ScreenSelector(QObject *parent = nullptr);
const QUrl ¤tScreen() const;
void setCurrentScreen(const QUrl &newCurrentScreen);
signals:
void currentScreenChanged();
private:
QUrl m_currentScreen;
QStateMachine m_statemachine; //instantiating a QStateMachine object
};
9. Integrated Computer Solutions Inc. www.ics.com
Creating States
QState *loggedInstate = new QState();
loggedInstate->setObjectName("LoggedIn");
loggedInstate->assignProperty(this, "currentScreen",
QUrl("CoolApplication.qml"));
QState *loggedOutState = new QState();
loggedOutState->setObjectName("LoggedOut");
loggedOutState->assignProperty(this, "currentScreen",
QUrl("LoginScreen.qml"));
QState *screnSaverMode = new QState();
screnSaverMode->setObjectName("ScrenSaverMode");
screnSaverMode->assignProperty(this, "currentScreen",
QUrl("ScreenSaver.qml"));
9
● Just create an instance of a QState
in the business logic
● QState represents a set of properties
and values
● The entry into a state triggers the
value setting of properties as
specified with the method
QState::assignProperty(QObject *,
char *, const QVariant &)
10. Integrated Computer Solutions Inc. www.ics.com
Creating a Superstate
QState *working = new QState(); //This is a super State
working->setObjectName("working");
QState *loggedInstate = new QState(working);
loggedInstate->setObjectName("loggedIn");
loggedInstate->assignProperty(this, "currentScreen",
QUrl("CoolApplication.qml"));
QState *loggedOutState = new QState(working);
loggedOutState->setObjectName("loggedOut");
loggedOutState->assignProperty(this, "currentScreen",
QUrl("LoginScreen.qml"));
QHistoryState *workingh = new QHistoryState(working);
working->setInitialState(loggedInstate);
10
Just create an instance of a QState and use
the parent/child relationship to specify the
state hierarchy
Set an initial state of the superstate with
QState::setInitialState(QAbstractState)
Take advantage of QHistoryState to reference
its last active sub-state
11. Integrated Computer Solutions Inc. www.ics.com
Adding States to the State Machine
QState *working = new QState(); //This is a super State
...
QState *loggedInstate = new QState(working);
...
QState *loggedOutState = new QState(working);
...
QHistoryState *workingh = new QHistoryState(working);
QState *screnSaverMode = new QState();
...
//Adding States to State Machine
m_statemachine.addState( working );
m_statemachine.addState( screnSaverMode );
m_statemachine.setInitialState( loggedInstate) ;
m_statemachine.start()
● Use void
QStateMachine::addState(QAbstract
State *state)
● Or make the states children of the
state machine
● Set the initial using void
QState::setInitialState(QAbstract
State *state)
● Don’t forget to start the machine
using void QStateMachine::start()
11
12. Integrated Computer Solutions Inc. www.ics.com
But What About the Transitions?
12
QState *loggedInstate = new QState(working);
...
QState *loggedOutState = new QState(working);
...
loggedOutState->addTransition(&m_communicationLayer,
&CommunicationLayer::loggedIn,
loggedInstate);
loggedInstate->addTransition(&m_communicationLayer,
&CommunicationLayer::loggedOut,
loggedOutState);
● Use QState::addTransition
● Can be used directly with instance of a QSignalTransition or QEventTransition
13. Integrated Computer Solutions Inc. www.ics.com
And What about the History and Super State?
13
QState *working = new QState(); //This is a super State
QHistoryState *workingh = new QHistoryState(working);
…
QState *screenSaverMode = new QState();
screenSaverMode->setObjectName("screnSaverMode");
screenSaverMode->assignProperty(this, "currentScreen",
QUrl("Screensaver.qml"));
working->addTransition(this, &ScreenSelector::inactiveForTooLong,
screenSaverMode);
screenSaverMode->addTransition(this, &ScreenSelector::wokenUp,
workingh);
● Still Use QState::addTransition
● The History state refers to the last active sub-state
14. Integrated Computer Solutions Inc. www.ics.com
Retrieving States from the State Machine
14
//Retrieving Logged Out State
QState* aState = m_statemachine.findChild<QState*>("loggedOut");
//Retrieving all States
QList<QState*> states =
m_statemachine.findChildren<QState*>( QRegularExpression(".*") );
//Retrieving Direct States
QList<QObject*> states = m_statemachine.children();
//Display current states of state machine upon entry of specialState
connect(*specialState, &QState::entered,
[this](){
qDebug() << m_statemachine.configuration();
}
);
● The QObject parent/child
relationship applies
● QStates are children of
QStateMachine
● The QObject findChild() and
findChildren() methods assist in
retrieving states
● QStateMachine::configuration() lists
the current states of a state
machine
15. Integrated Computer Solutions Inc. www.ics.com
Conditional Transitions
15
class ConditionalTransition : public QSignalTransition {
Q_OBJECT
Q_PROPERTY(bool canTrigger READ canTrigger WRITE setCanTrigger)
public:
ConditionalTransition(QState * sourceState = 0): QSignalTransition(sourceState)
{
m_canTrigger = false;
}
void setCanTrigger(bool v) { m_canTrigger = v; }
bool canTrigger() const { return m_canTrigger; }
protected:
bool eventTest(QEvent *e) {
if(!QSignalTransition::eventTest(e))
return false;
return canTrigger(); }
private:
bool m_canTrigger;
}
● Somewhat tricky
● Requires the re-implementation of
a transition class
● And the re-implementation of
bool eventTest(QEvent *event)
● Return true if the condition is met
16. Integrated Computer Solutions Inc. www.ics.com
Advantages of Using the State Machine Framework
16
● Allows for Graphical State Machine Designer Tooling.
Examples:
● Qt SCXML https://doc.qt.io/qt-5/qtscxml-overview.html,
● KDAB State machine Editor
https://github.com/KDAB/KDStateMachineEditor
● Would allow for analysis of the overall logic
● Allows for easy and precise documentation of requirements