PDA

View Full Version : QState



cszawisza
6th November 2014, 16:36
Hi!

I have a dialog with comboBox, couple of line edits and other stuff. In comboBox I have several entries that define what fields should be disabled and witch shouldn't be.

What I want to achieve is simple, when current index in comboBox changes, application should go to state defined by index of newly selected item. Now everything is handled by if else statements, but i decided to use QStateMachine instead.
When indexes in comboBox change in one direction, everything workis fine:
state1 -> state2;
state2 -> state3;
state3 -> state4;
To define two way index change I neeed to add new transactions to state machine, that will les the state machine to go back
state1 -> state2; // UP
state1 -> state4; // DOWN
state2 -> state3;
state2 -> state1;
state3 -> state4;
state3 -> state2;
state4 -> state1;
state4 -> state3;

To this works if user uses scroll to go through all comboBox fields, but when he choose something by clicking it (e.g. index from 4 to 2) I have no transaction that can handle this "action", so I need to add more transactions... In other words I need to write ALL-TO-ALL transactions to achieve what I want.
Is there another way of doing something like this? some kind of "stateless stateMachine" or a mechanism that can by used to "call" specific state?
I know stat state machine is designed not to do something like I want, but it is quite easy to use and it's simpler then write own code :)

wysota
6th November 2014, 19:01
Cam you show some code to demonstrate what you have? It is hard to make anything out from your description.

cszawisza
7th November 2014, 07:51
10735
This is a simple test project that contains a state machine. Please compile this, click "State up" button, and then try to change index of comboBox and observe the behavior of checkBoxes on the right, this is the desired behavior (move from one state to any other). Then look on mainwindow.cpp file lines 76 to 94, those are needed transactions for this kind of behavior, there is a lot of code... but this is not the worst news. When I add an item to comboBox, I need to define n-1 more transitions (where n is number of items in comboBox).

I didn't know how to add a transitions to SIGNALs attribute, so I decided to create a simple class that emits a signal depending on index of selected in comboBox index and base transitions on that signal instead.

I know that I can use signal and slots mechanism to control the ui behavior, but this approach has something that I don't know how to implement (in simple way) in SLOT and that is... QStateMachine::setGlobalRestorePolicy(QState::Rest oreProperties);

I hope that this description of my problem is better :)

anda_skoa
7th November 2014, 08:54
If you need a transition that evaluates signal arguments and only triggers on certain values, have a look at http://qt-project.org/doc/qt-5/qsignaltransition.html

Cheers,
_

wysota
7th November 2014, 09:01
Did you try simply grouping states?

Something alone the lines of:


QState *masterState = new QState;
QState *s1 = new QState(masterState);
QState *s2 = new QState(masterState);
QState *s3 = new QState(masterState);
QState *s4 = new QState(masterState);
masterState->setInitialState(s1);
machine.addState(masterState);
masterState->addTransition(signalEmitter, SIGNAL(received_1()), s1);
masterState->addTransition(signalEmitter, SIGNAL(received_2()), s2);
masterState->addTransition(signalEmitter, SIGNAL(received_3()), s3);
masterState->addTransition(signalEmitter, SIGNAL(received_4()), s4);

cszawisza
7th November 2014, 09:53
Wysota, thanks for answer, but unfortunately, I didn't understand you or your state machine is a "one way ticket" machine ;)


QState *masterState = new QState;
QState *s1 = new QState(masterState);
QState *s2 = new QState(masterState);
QState *s3 = new QState(masterState);
QState *s4 = new QState(masterState);
masterState->setInitialState(s1);
machine.addState(masterState);
masterState->addTransition(signalEmitter, SIGNAL(received_1()), s1);
masterState->addTransition(signalEmitter, SIGNAL(received_2()), s2);
masterState->addTransition(signalEmitter, SIGNAL(received_3()), s3);
masterState->addTransition(signalEmitter, SIGNAL(received_4()), s4);


You got only one way transitions, when you go to state s1, you don't have any transition that will let you to go back from it... Or I'd simply not understand you. Please came back with a more extensive example

anda_skoa for this example I didn't need this kind of functionality, but I'll probably need this in the future, thanks for answer :)

wysota
7th November 2014, 13:17
Did you try my code? The idea is that all the child states inherit transitions from the parent state so each of the four transitions defined in the parent state should work in any of the child states. I haven't tested it but it should work, if I understood the docs correctly.

cszawisza
9th November 2014, 12:04
I tried to get it working, but unfortunately I get stuck in initial child state :(