[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());
    }
    @


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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 :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.