We have been studying Qt and decided to develop a small chat client project for Maemo. One of the mandatory requirements was the Qt Animation Framework usage. Just for test, or to learn, we designed our application as a big state machine.
Another design decision was to use MVC. But, how integrate model-view-controller and state machine? Well, as you know, views should handle all canvas and animations (if exist). Given this scenario, we splitted states into two types: macro-states and sub-states. Macro-states are the controllers and sub-states are contained by views. Views are responsible by their sub-states processing. Each view have a state called “doneState” which is used to inform respective controller that view is ok to be deleted.
The picture below tries to make it more clear to understand:

The transitions inside views are not early defined. If a view has an animation, it is probably that will exist a transition from “static state” to “animation state” inside view state.
Today, Abil (this is the name for the project), has a splash screen, login screen and buddy list screen. The picture above just shows the interaction between splash and login but all components have the same composition: a controller which contains a view. The controller itself is a state and the view has sub-states for static and animation.
The state machine is used to control the screen transitions and to de/allocate controllers. Transitions from splash to login, from login to buddy list screens were defined. But, how implement these transitions without instatiate each controller?
We used Qt Meta Objects to do this job. See code snipped below:
<code>
QtStateMachine machine;
QtFinalState *doneState = new QtFinalState(machine.rootState());
AbilState mainState(MainCtrl::staticMetaObject, &scene, machine.rootState());
AbilState splashState(SplashCtrl::staticMetaObject, &scene, &mainState);
AbilState loginState(LoginCtrl::staticMetaObject, &scene, &mainState);
AbilState buddyState(BuddyCtrl::staticMetaObject, &scene, &mainState);
splashState.addFinishedTransition(&loginState);
loginState.addFinishedTransition(&buddyState);
buddyState.addFinishedTransition(&loginState);
mainState.setInitialAbilState(&splashState);
mainState.addFinishedTransition(doneState);
QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
machine.setInitialState(&mainState);
machine.start();QtStateMachine machine;
QtFinalState *doneState = new QtFinalState(machine.rootState());
AbilState mainState(MainCtrl::staticMetaObject, &scene, machine.rootState());
AbilState splashState(SplashCtrl::staticMetaObject, &scene, &mainState);
AbilState loginState(LoginCtrl::staticMetaObject, &scene, &mainState);
AbilState buddyState(BuddyCtrl::staticMetaObject, &scene, &mainState);
splashState.addFinishedTransition(&loginState);
loginState.addFinishedTransition(&buddyState);
buddyState.addFinishedTransition(&loginState);
mainState.setInitialAbilState(&splashState);
mainState.addFinishedTransition(doneState);
QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
machine.setInitialState(&mainState);
machine.start();
</code>
Controllers are not instantiated until the last moment. :) But, we are able to add transitions for macro-states. I’ll explain better this solution in another post.
briglia Qt