Qt State Machine Framework

Hopefully there won't be a public outcry when I claim that most Qt applications can be described as "a set of objects that interact with eachother over a period of time". It's the job of Qt to provide APIs that support this process. Today I'd like to focus on the "over a period of time" part.

Whereas class diagrams describe structure, state diagrams describe behavior. This is what a state diagram for a simple checkbox might look like:

In an object-oriented language like C++, there's usually a one-to-one mapping between the elements of a class diagram and the code -- classes are a fundamental part of the language, after all. With state diagrams there isn't any such direct correspondence, though; they're foreign tongue.

For "trivial" things (like a checkbox) you can quickly code something that works, of course, without using any concepts from state diagrams directly. However, because of the nature of event-driven programs (most Qt applications are), it's very easy to end up with a bunch of if- and switch-statements that try to determine what the application should do at each point. Because the state of the application is implicit (just a bunch of variables), it soon gets difficult to understand what's going on, which cases you've covered and which you haven't. And don't ever try to change or add something because that'll just break everything.

The alternative to the ad hoc implementations of state machines described above is to rely on a framework to help you out. To this end, we're working on a State Machine Framework that makes Qt speak the language of state diagrams; it lets you construct state graphs and execute them. The goal is to enable applications to have a cleaner separation between control flow and actual useful work. It's pretty much an event loop with a control flow mechanism on top.

The framework integrates deeply with Qt's event system, signals and slots, and property system. By making it a core technology in Qt, the threshold for starting to use it should be very low, so that as many applications as possible can benefit from it. Inside Qt this framework is being used in conjunction with the new Animations Framework to provide animated transitions. Since the State Machine framework implements the algorithm defined by SCXML, we also aim to make it the backend of Qt SCXML.

OK, time to implement our first state machine. Consider the following state diagram:

Every time the button button is clicked, the state machine transitions to another state, and button's text property is changed to reflect which state the machine is now in. Here's how it can be implemented using the Qt State Machine API:

#include <QtGui>

int main(int argc, char **argv)
{
QApplication app(argc, argv);
QPushButton button;

QStateMachine machine;

QState *s1 = new QState(machine.rootState());
s1->setPropertyOnEntry(&button, "text", "In s1");

QState *s2 = new QState(machine.rootState());
s2->setPropertyOnEntry(&button, "text", "In s2");

QState *s3 = new QState(machine.rootState());
s3->setPropertyOnEntry(&button, "text", "In s3");

s1->addTransition(&button, SIGNAL(clicked()), s2);
s2->addTransition(&button, SIGNAL(clicked()), s3);
s3->addTransition(&button, SIGNAL(clicked()), s1);

button.resize(200, 200);
button.show();

machine.setInitialState(s1);
machine.start();

return app.exec();
}

You can have a slot get called whenever a state is entered; or you can subclass Q(Abstract)State and do whatever you like. There's a mechanism for having transitions based on events (e.g. mousePress). You can have composite (nested) states, parallel states... It's pretty powerful stuff. Oh yeah, in case I forgot to mention, I'm pretty excited about this! :D If I had to pick, this is the one thing I've felt was missing since I started using Qt. Death to spaghetti code, long live control abstractions.

The State Machine Framework is part of the Qt Kinetic project. You'll find it in the kinetic-animations branch of the Qt Kinetic repository. Have fun, and let us know what you think.


Blog Topics:

Comments