c++ - Emitting signals from class, if transition in QStateMachine was successful -
my problem following: need create class, contains qstatemachine instance. class should have slots through "ask" state machine make transition state. , if transition successful, class should emit signal it. how implement this? class should have ability emit signals according slot invoke. here small example of class:
class myclass : public qobject { q_object public: explicit myclass(qobject *parent = 0) { mstatemachine = new qstatemachine(this); qstate *s1 = new qstate(mstatemachine); qstate *s2 = new qstate(mstatemachine); qstate *s3 = new qstate(mstatemachine); s1->addtransition(); // transition s2 s2->addtransition(); // transition s3 s3->addtransition(); // transition s1 mstatemachine->setinitialstate(s1); mstatemachine->start(); } signals: tos1(); tos2(); tos3(); public slots: slottos1() { /* post event state machine transition state s1, if transition successful, emit tos1() signal. */ }; slottos2(){ /* similar slottos1 */}; slottos3(){ /* similar slottos1 */}; private: qstatemachine *mstatemachine; } i grateful help!
upd:
slots representing defferent kinds of transitions, outer class (that using myclass) 'ask' transition. so, slot send event or signal state machine, looks on event or signal , (if in right state) makes transition. , want notify outer class signal, asked before slot (transition) made successfuly.
to transition on slot call, need somehow bind slot
qabstracttransition. there 2 ways of doing it:use
qeventtransition, send relevant event trigger it.use
qsignaltransition, use internal signal trigger it.
to emit signals on state transitions, can connect
qabstracttransition::triggeredorqstate::enteredorqstate::exitedsignals other signals. remember, in qt connection target can either slot or signal.
thus, using signal transitions:
class myclass : public qobject { q_object qstatemachine machine; qstate s1, s2; q_signal void s_go_s1_s2(); q_signal void s_go_s2_s1(); public: q_signal void transitioned_s1_s2(); q_signal void transitioned_s2_s1(); q_slot void go_s2_s1() { emit s_go_s2_s1(); } q_slot void go_s1_s2() { emit s_go_s1_s2(); } explicit myclass(qobject *parent = 0) : qobject(parent), s1(&machine), s2(&machine) { auto s1_s2 = s1.addtransition(this, signal(s_go_s1_s2()), &s2); auto s2_s1 = s2.addtransition(this, signal(s_go_s2_s1()), &s1); machine.setinitialstate(&s1); machine.start(); connect(s1_s2, &qabstracttransition::triggered, this, &myclass:: transitioned_s1_s2); connect(s2_s1, &qabstracttransition::triggered, this, &myclass:: transitioned_s2_s1); } } using event transitions bit harder, since events you're using must cloneable state machine. core module's state machine knows how clone none , timer events - see cloneevent implementation.
the widgets module adds support various gui/widgets events - see cloneevent implementation there. could, in pinch, use such gui events own purposes - after all, sent plain qobject doesn't interpret them in special way.
you can provide own cloneevent implementation links others.
#include <private/qstatemachine_p.h> class myclass : public qobject { q_object qstatemachine machine; qstate s1, s2; qevent e_s1_s2, e_s2_s1; qeventtransition s1_s2, s2_s1; public: q_signal void transitioned_s1_s2(); q_signal void transitioned_s2_s1(); q_slot void go_s2_s1() { qcoreapplication::sendevent(this, &e_s2_s1); } q_slot void go_s1_s2() { qcoreapplication::sendevent(this, &e_s1_s2); } explicit myclass(qobject *parent = 0) : qobject(parent), s1(&machine), s2(&machine), e_s1_s2((qevent::type)(qevent::user + 1)), e_s2_s1((qevent::type)(qevent::user + 2)), s1_s2(this, e_s1_s2.type()), s2_s1(this, e_s2_s1.type()) { s1_s2.settargetstate(&s2); s2_s1.settargetstate(&s1); s1.addtransition(&s1_s2); s2.addtransition(&s2_s1); machine.setinitialstate(&s1); machine.start(); connect(&s1_s2, &qabstracttransition::triggered, this, &myclass::transitioned_s1_s2); connect(&s2_s1, &qabstracttransition::triggered, this, &myclass::transitioned_s2_s1); } } static const qstatemachineprivate::handler * last_handler = 0; static qevent * cloneevent(qevent * e) { if (e->type() >= qevent::user && e->type() < qevent::user+100) { return new qevent(e->type()); return last_handler->cloneevent(e); } const qstatemachineprivate::handler our_handler = { cloneevent }; void registerhandler() { last_handler = qstatemachineprivate::handler; qstatemachineprivate::handler = &our_handler; } q_constructor_function(registerhandler()) void unregisterhandler() { qstatemachineprivate::handler = last_handler; } q_destructor_function(unregisterhandler())
Comments
Post a Comment