Results 1 to 6 of 6

Thread: QStataMachine: transition guards

  1. #1
    Join Date
    Jun 2011
    Posts
    25
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default QStataMachine: transition guards

    Hi all,

    I basically have a QStateMachine with 3 states: A, B and C.
    I want to model state machine transitions like:
    1) A -> B [event e1]
    2) A -> C [event e1]
    3) B -> C [event e2]

    And I want to add exclusive guard on transitions #1 and #2 like:
    1) if (myModel.v)
    3) if (!myModel.v)

    The final goal is to manage locking of access from A to C by inserting password:
    when I am in A and fire e1 (for example by clicking on a button in my GUI):
    - if "myModel.v" is not set (i.e. C is still locked by password) go to state B (to insert password)
    - if "myModel.v" is set (that is C was unlocked) go to state C.

    What is the best way to add these guards on transitions?
    Can you give me a small example?

    Thank you,

    Nicola
    Last edited by nick85; 26th September 2013 at 13:24.

  2. #2
    Join Date
    Jun 2011
    Posts
    25
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QStataMachine: transition guards

    I've tried to follow the documentation http://qt-project.org/doc/qt-4.8/sta...ons-and-guards
    but it does not seem to fully contemplate my case.

    Here is part of code:

    The state machine:
    Qt Code:
    1. StateMachine::StateMachine(bool debugMode, QObject *parent)
    2. : QStateMachine(parent)
    3. {
    4. _a = new State();
    5. _b = new State();
    6. _c = new State();
    7.  
    8. addState(_a);
    9. addState(_b);
    10. addState(_c);
    11.  
    12. addConditionalTransition(_a, true, _b);
    13. addConditionalTransition(_a, true, _c);
    14. addCustomTransition(_b, this, SIGNAL(goToCSigna()),_c);
    15. }
    16.  
    17. QSignalTransition* StateMachine::addCustomTransition(State* source,
    18. const char* signal,
    19. QAbstractState* target)
    20. {
    21. QSignalTransition* transition = source->addTransition(sender,signal,target);
    22. connect(transition,SIGNAL(triggered()),this,SLOT(_onStateChanged()));
    23. return transition;
    24. }
    25.  
    26. ConditionalTransition *StateMachine::addConditionalTransition(State *source,
    27. bool condition,
    28. QAbstractState *target)
    29. {
    30. ConditionalTransition * transition = new ConditionalTransition(condition);
    31. transition->setTargetState(target);
    32. source->addTransition(transition);
    33. connect(transition,SIGNAL(triggered()),this,SLOT(_onStateChanged()));
    34. return transition;
    35. }
    36.  
    37. // SLOT of state machine used for debug
    38. void StateMachine::_onStateChanged()
    39. {
    40. if(QSignalTransition* transition = qobject_cast<QSignalTransition*>(this->sender()))
    41. {
    42. qDebug() << "Changing State" <<
    43. "from:" << transition->sourceState()->objectName() <<
    44. "to:" << transition->targetState()->objectName();
    45. }
    46. }
    47.  
    48. // Q_INVOKABLE method to use state machine postEvent
    49. void StateMachine::invokablePostEvent(bool b)
    50. {
    51. this->postEvent(new ConditionalEvent(b));
    52. }
    To copy to clipboard, switch view to plain text mode 

    The custom transition:
    Qt Code:
    1. class ConditionalTransition : public QAbstractTransition
    2. {
    3. public:
    4. ConditionalTransition(bool condition);
    5.  
    6. protected:
    7. virtual bool eventTest(QEvent *e);
    8. virtual void onTransition(QEvent *) {}
    9.  
    10. bool _condition;
    11. };
    12.  
    13. // implementation ------------------------------------
    14. ConditionalTransition::ConditionalTransition(bool condition) :
    15. _condition(condition)
    16. {
    17. }
    18.  
    19. bool ConditionalTransition::eventTest(QEvent *e)
    20. {
    21. // Test if this event is a ConditionalEvent
    22. if (e->type() != QEvent::Type(QEvent::User+1))
    23. return false;
    24.  
    25. ConditionalEvent *se = static_cast<ConditionalEvent*>(e);
    26.  
    27. return (se->value == _condition);
    28. }
    To copy to clipboard, switch view to plain text mode 

    The custom event:
    Qt Code:
    1. struct ConditionalEvent : public QEvent
    2. {
    3. ConditionalEvent(bool val);
    4.  
    5. bool value;
    6. };
    7.  
    8. // implementation ------------------------------------
    9. ConditionalEvent::ConditionalEvent(bool val) :
    10. QEvent(QEvent::Type(QEvent::User+1)),
    11. value(val)
    12. {
    13. }
    To copy to clipboard, switch view to plain text mode 

    And finally, into a button of QML GUI, the caller:
    Qt Code:
    1. MyButton
    2. {
    3. id: myButton
    4. [...]
    5. onClicked: stateMachine.invokablePostEvent(dataModel.val)
    6. }
    To copy to clipboard, switch view to plain text mode 


    CustomTransitions have no problem.
    ConditionalTransition seems not works... when I'm in state _a and click on myButton, the transition is not triggered (I do not see output of lost _onStateChanged).

    What is wrong?
    Or, otherwise, what is the way to check the condition?


    Added after 33 minutes:


    I found the problem of the trigger:
    the cast had to be to QAbstractTransition instead of QSignalTransition.

    Now the statemachine works but what I wonder is whether it is necessary to write all this code to add a simple guard of the transition.
    Or rather, if it is not possible to execute a "conditional transition" when is rised a signal like "addCustomTransition"s.
    Last edited by nick85; 26th September 2013 at 14:52.

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QStataMachine: transition guards

    well, you wouldn't need to subclass QStateMachine but maybe you want to do that for a different reason.

    Since you are triggering this from QML and on a button click:

    - create a context propery object that has a slot or Q_INVOKABLE method that the button triggers
    - in that slot you check the condition and emit one of two different signals
    - you have two signal transition on your state, one for each signal

    Such a signal source is a very common way to interface a QStateMachine from QML. QML code triggers signal emits on the object, the signals trigger transitions.
    The object can also hold properties that are set by state machine states, in case that the QML code wants to do things in certain states, like hiding/showing certain elements.

    Cheers,
    _

  4. The following user says thank you to anda_skoa for this useful post:

    nick85 (27th September 2013)

  5. #4
    Join Date
    Jun 2011
    Posts
    25
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QStataMachine: transition guards

    Ok this is right and it certainly works.. but doing it the state machine control (i.e. the valutation of the condition) is moved inside the QML and I think this may be not conceptually correct.

  6. #5
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QStataMachine: transition guards

    I am not sure what you mean.

    The state machine is part of the application code, independent of the UI.
    The UI, well the user through the UI, generates changes, some of which make the state machine change states.
    The UI reacts to state changes when appropriate, independent of how the state change was triggered.

    In that model the UI doesn't know anything about the state machine and the state machine doesn't know anything about the UI.

    Cheers,
    _

  7. #6
    Join Date
    Apr 2015
    Posts
    9
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: QStataMachine: transition guards

    More modern termplate based version:
    Qt Code:
    1. template<typename T>
    2. class GuardedTransition : public T
    3. {
    4. public:
    5. static_assert(std::is_convertible<T*, QAbstractTransition*>::value,
    6. "GuardedTransition must inherit QAbstractTransition");
    7.  
    8. template <class... Args>
    9. GuardedTransition(function<bool()> g, Args&&... args)
    10. : T(std::forward<Args>(args)...), guard(g) {}
    11.  
    12. bool eventTest(QEvent *e) override
    13. { return T::eventTest(e) && guard(); }
    14.  
    15. private:
    16. function<bool()> guard;
    17. };
    To copy to clipboard, switch view to plain text mode 

    Did not find out how to use the std::index stuff to make the guard the last parameter yet. However using this state transitions are finally somewhat readable:

    Qt Code:
    1. static void addEventTransition(QState &src, QState &tgt,
    2. QObject *object, QEvent::Type type,
    3. function<bool()> guard = nullptr)
    4. {
    5. QAbstractTransition *t;
    6. if (guard)
    7. t = new GuardedTransition<QEventTransition>(guard, object, type, &src);
    8. else
    9. t = new QEventTransition(object, type, &src);
    10. t->setTargetState(&tgt);
    11. }
    12.  
    13. template <typename Func>
    14. static void addSignalTransition(QState &src, QState &tgt,
    15. const typename QtPrivate::FunctionPointer<Func>::Object *sender,
    16. Func signal,
    17. function<bool()> guard = nullptr)
    18. {
    19. QAbstractTransition *t;
    20. if (guard)
    21. t = new GuardedTransition<QSignalTransition>(guard, sender, signal, &src);
    22. else
    23. t = new QSignalTransition(sender, signal, &src);
    24. t->setTargetState(&tgt);
    25. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. addSignalTransition(
    2. settings_button_highlight, settings_button_visibile,
    3. window, &Window::queryChanged,
    4. [=] { window->input_frame.underMouse(); });
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. Replies: 3
    Last Post: 2nd September 2013, 18:01
  2. How to know the signal which caused a qstate transition
    By ClintEastwood in forum Qt Programming
    Replies: 6
    Last Post: 24th April 2013, 15:27
  3. Replies: 2
    Last Post: 16th November 2010, 06:11
  4. Transition from QMainWindow to QWidget
    By Sabre Runner in forum Newbie
    Replies: 5
    Last Post: 12th October 2010, 16:05
  5. Qt3 to Qt4 transition, setWindowIcon() problems
    By watashi16 in forum Qt Programming
    Replies: 5
    Last Post: 13th December 2007, 20:18

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.