[Qt-interest] QStateMachine API and design?
Sean Harmer
sean.harmer at maps-technology.com
Thu Nov 4 15:51:06 CET 2010
Hi,
On Thursday 04 November 2010 14:03:22 Stephen Kelly wrote:
> Yes. I haven't figured out what parallel states are for though tbh.
We have mainly made use of them where in some hardware devices we have
multiple subsystems which are more or less independent (although you can still
have some dependencies between them using guardded transitions).
For example we have a SM with 15 subsystems representing 15 pieces of a type
of pcb and an overall "system mode" state. All of these are arranged under a
top-level state as 16 parallel states. Each of these then has substates in the
usual manner. The system mode state and each pcb are mostly independent but
are part of the same SM because the system mode initiates actions on each of
the pcb's and the pcb's notify progress by posting events to the SM. Then all
pcb's have performed a required task then the system mode gets updated.
NB: In turn each of the pcb's are QObjects that themselves contain a SM that
manages the inner logic of the pcb's. I find it helps to keep the SM's
relatively self-contained and as simple as possible rather than having a
single monolithic one.
Applying this to a GUI, you could envisage using parallel states if you have
several widgets on a form that are more or less independent. For example a
dialog with two tab widgets on them. The current tab for each tab widget could
be managed by a SM containing two parallel states.
> >> * Why is there no notification when the 'current state' is changed?
> >
> > I have filed a bug for this after discussion with Kent:
> >
> > http://bugreports.qt.nokia.com/browse/QTBUG-9380
> >
> > Please vote for it or file a MR. It should be asimple change and it is on
> > my list but time as always is short. A graphical SM debugger would also
> > be *very* nice but that's a much larger task.
>
> Done.
Cool thanks.
> I connect to the entered() signal as you suggested and connect it to a
> custom stateChanged() slot on the statemachine itself, while the transition
> updates the state Q_PROPERTY of the state machine.
>
> http://websvn.kde.org/trunk/KDE/kdepim/mobile/lib/statemachinebuilder.cpp?v
> iew=markup
>
> > Or you can implement the
> > onEntry()/onExit() functions in your own custom states. We have largely
> > gone for custom states and used overridden onEntry() functions. Not sure
> > if any of these would map cleanly onto a Qml scene though as I have not
> > tried it in anger yet.
>
> I would be interested in how you think it could work, or to see what one of
> your onEntry implementations look like.
OK. I'll see if I can put together a simple Qml + SM example. I may have some
time this evening.
Here is a sample onEntry() implementation as an example. It is nothing
special:
void MeasureAtState::onEntry( QEvent* e )
{
FrChildState::onEntry( e );
emit measurementStarted();
// Kick off a measurement.
childSystem()->measure( m_measureSettings );
}
In this case the MeasureAtState is derived from FrChildState which in turn is
derived from a simple State helper class which I have attached to this mail.
The State class has it's onEntry()/onExit() functions overridden to print out
a qDebug() msg of as the SM enters/exits states (along with the parent
states). I found this to be invaluable during debugging SMs.
In the above example it was not possible to hook up the MeasureAtState
instance's entered() signal to the childSystem()'s measure signal as we needed
to pass in some arguments to the measure() function. I admit that this leads
to some coupling between the SM and the objects it is managing but that is OK
IMO as the whole thing is then encapsulated in another QObject class anyway.
The wider application never deals with the SM directly.
In such cases we have also taken the approach of having a custom class be
responsible for creating its child states rather than having all states and
parent-child relationships set up by a single function. Something like this:
ModeState::ModeState( FrSystem* system, QState* parent )
: FrSystemState( system, "FrSystem Mode", parent ),
m_starting( new StartingState( system, this ) ),
m_running( new RunningState( system, this ) ),
m_pausing( new PausingState( system, this ) ),
m_error( new ErrorState( system, this ) )
{
setInitialState( m_starting );
// Final state
QFinalState* final = new QFinalState( this );
// As soon as the starting state has done its work we immediately
transition
// to the running state.
m_starting->addTransition( m_running );
// We then need transitions to/from the paused state...
PausingTransition* pausingTransition = new PausingTransition( system,
m_running );
pausingTransition->setTargetState( m_pausing );
m_running->addTransition( pausingTransition );
CustomEventTransition* unpauseTransition =
new CustomEventTransition( QEvent::Type( QEvent::User +
FrHardware::UnpauseEventOffset ), m_pausing );
unpauseTransition->setTargetState( m_running );
m_pausing->addTransition( unpauseTransition );
// Adding transitions to/from the error state...
ErrorTransition* errorTransition = new ErrorTransition( system, m_running
);
errorTransition->setTargetState( m_error );
m_running->addTransition( errorTransition );
m_error->addTransition( m_running );
// Add a transition from the running state to the final state when all
enabled probes are in the notMeasuring state
StoppingTransition* trans1 = new StoppingTransition( system, m_running );
trans1->setTargetState( final );
m_running->addTransition( trans1 );
}
Then in turn the RunningState ctor is responsible for creating its nested
child states etc.
I find that this makes it easier to understand, debug and maintain a sub-tree
of states more easily. Both approaches are valid though.
Hope this helps a litle.
Cheers,
Sean
-------------- next part --------------
A non-text attachment was scrubbed...
Name: state.cpp
Type: text/x-c++src
Size: 1126 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20101104/dc443bc8/attachment.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: state.h
Type: text/x-chdr
Size: 668 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20101104/dc443bc8/attachment-0001.bin
More information about the Qt-interest-old
mailing list