[solved] When it is better to use a user event vs user signal for QStateMachine transitions?
-
I am just starting a project where I will use a QStateMachine. It appears I will have several transitions I will want to trigger myself, unrelated to any existing signal or event. My question is what are the reasons to prefer custom signals which I create vs custom events which I create. I'm looking for the general pros and cons since I haven't designed all the states and transitions yet, but here is one example to make it clearer.
To use a custom signal I think it would look something like this:
@
// MainWindow code
QStateMachine stateMachine;
// Setup custom state so it can trigger the transition when it wants.
State* stateSplashScreen = new SplashScreenState(&stateMachine);
State* stateSleep = new State(&stateMachine);
// Setup transition using a signal.
stateSplashScreen->addTransition(stateSplashScreen, SIGNAL(finishedNoUser()), stateSleep);
// Start state machine
stateMachine.start();// Custom state description
class SplashScreenState : public State
{
Q_OBJECT
public:
explicit SplashScreenState(QState parent = 0);
signals:
void finishedNoUser();
protected slots:
void exit();
protected:
virtual void onEntry(QEvent event);
protected:
QTimer m_stateTimer;
};// Custom state implimentation
SplashScreenState::SplashScreenState(QState *parent) :
State(parent),
m_stateTimer(this)
{
// Set up state timer to reach exit() when time has expired.
m_stateTimer.setInterval(1000);
m_stateTimer.setSingleShot(true);
connect(&m_stateTimer, SIGNAL(timeout()), this, SLOT(exit()));
}// Start timer upon entry to state.
void SplashScreenState::onEntry(QEvent* event)
{
Q_UNUSED(event);
m_stateTimer.start();
}void SplashScreenState::exit()
{
// Some complicated code that selectively if we
// really want to exit, or do something more in this state.
// Decides we want to leave in a way that will go to sleepState.
emit finishedNoUser();
}
@
To use a custom signal I think it would look something like this:
@
// MainWindow code
QStateMachine stateMachine;
// Setup custom state so it can trigger the transition when it wants.
State* stateSplashScreen = new SplashScreenState(&stateMachine);
State* stateSleep = new State(&stateMachine);
// Setup transition using an event.
FinishedNoUserTransition* finishedNoUserTransition = new FinishedNoUserTransition();
finishedNoUserTransition->setTargetState(stateSleep);
stateSplashScreen->addTransition(finishedNoUserTransition);
// Start state machine
stateMachine.start();// Custom event description
class FinishedNoUserEvent : public QEvent
{
public:
FinishedNoUserEvent() : QEvent(QEvent::Type(QEvent::User + 1) )
{}
};
// Custom transition description
class FinishedNoUserTransition : public QAbstractTransition
{
public:
FinishedNoUserTransition() {}
protected:
virtual bool eventTest(QEvent *e)
{
return (e->type() == QEvent::User + 1);
}
virtual void onTransition(QEvent *)
{}
};// Custom state description
class SplashScreenState : public State
{
Q_OBJECT
public:
explicit SplashScreenState(QState parent = 0);
protected slots:
void exit();
protected:
virtual void onEntry(QEvent event);
protected:
QTimer m_stateTimer;
};// Custom state implimentation
SplashScreenState::SplashScreenState(QState *parent) :
State(parent),
m_stateTimer(this)
{
// Set up state timer to reach exit() when time has expired.
m_stateTimer.setInterval(1000);
m_stateTimer.setSingleShot(true);
connect(&m_stateTimer, SIGNAL(timeout()), this, SLOT(exit()));
}// Start timer upon entry to state.
void SplashScreenState::onEntry(QEvent* event)
{
Q_UNUSED(event);
m_stateTimer.start();
}void SplashScreenState::exit()
{
// Some complicated code that selectively if we
// really want to exit, or do something more in this state.
// Decides we want to leave in a way that will go to sleepState.
machine()->postEvent(new FinishedNoUserEvent());
}
@ -
Hi and welcome to devnet,
The selection of one versus the other is essentially a question of which one describes the best the reason for the transition e.g. if you were using your state machine to model a hardware device, you would probably use both but for different purpose like you have a the doubleClicked signal where it make sense but on standard widget you have to handle it through an event.
Hope it helps
-
Thanks for the ideas. Here's what I've noticed:
For QStateMachines it "appears":http://qt-project.org/doc/qt-4.8/statemachine-api.html#events-transitions-and-guards both end up as events. So, there is no reason to choose one over the other for control flow.
The code (see original posting) for signals looks simpler to me.
Signals probably work best for "simple argument types":http://qt-project.org/doc/qt-4.8/signalsandslots.html#signals.
So, I think I'll mainly use signals for my internally generated transition triggers, unless I need to pass complex data with them.
-
You're welcome !
If that answers your question, please update the thread title prepending [solved] so other forum users may know a solution has been found :)