I'm having some trouble with the Qt State Machine. I'm never able to execute the states: I get various types of errors and I can't figure out what is the problem. Please see below for more information on the errors and the code that leads to them.
This is my main function:
int main(int argc, char *argv[])
{
// Initialize the app
// ... app initialization here
QApplication app(argc, argv);
// Create the state machine
QStateMachine machine;
MyState* ms1 = new MyState("ms1");
MyState* ms2 = new MyState("ms2");
QFinalState* fs = new QFinalState();
ms1->addTransition(ms2);
ms2->addTransition(fs);
machine.addState(ms1);
machine.addState(ms2);
machine.addState(fs);
machine.setInitialState(ms1);
QObject::connect(&machine, SIGNAL(finished()), new Finisher(), SLOT(OnFinished()));
machine.start();
return app.exec();
}
I set break points in MyState
, but the break points never get hit and the start
/stop
methods never execute (I actually only expect start
to be called). The application goes directly into the Finisher::OnFinished
method.
Here is my state class:
class MyState: public QState
{
Q_OBJECT
private:
QString _stateName;
public:
MyState(QString stateName, QState * parent = 0):QState(parent), _stateName(stateName){}
~MyState(){}
public slots:
void start()
{
qDebug() << _stateName << " start.";
emit finished();
}
void stop()
{
qDebug() << _stateName << " stop.";
}
signals:
void finished();
//void exited();
};
The Finisher is pretty simple:
class Finisher:public QObject
{
Q_OBJECT
public slots:
void OnFinished()
{
qDebug() << "Finished!";
QTimer::singleShot(0, QApplication::instance(), SLOT(quit()));
}
};
I've tried several things, including setting the parent of each state directly:
// If I use the following code, I get an error
// stating that "the state has already been added to this machine"
MyState* ms1 = new MyState("ms1");
MyState* ms2 = new MyState("ms2", ms1);
QFinalState* fs = new QFinalState(ms2);
ms1->addTransition(ms2);
ms2->addTransition(fs);
machine.addState(ms1);
machine.addState(ms2);
machine.addState(fs);
machine.setInitialState(ms1);
// .. and so on
However, when it seems that I can't add the states when the machine.addState
is called:
QStateMachine::addState: state has already been added to this machine
QStateMachine::addState: state has already been added to this machine
Unrecoverable error detected in running state machine: Missing initial state in
compound state ''
I've also tried just leaving the constructors and not calling machine.addState
:
QStateMachine machine;
MyState* ms1 = new MyState("ms1");
MyState* ms2 = new MyState("ms2", ms1);
QFinalState* fs = new QFinalState(ms2);
ms1->addTransition(ms2);
ms2->addTransition(fs);
machine.setInitialState(ms1);
// .. and so on
However, in this case I get the following errors:
QState::setInitialState: state 0xa05e5e0 is not a child of this state (0x43fe94)
QStateMachine::start: No initial state set for machine. Refusing to start.
The last one is strange because I explicitly state the initial state to ms1
and then I call start
, so I don't know what's the problem there. Does anybody have any ideas on how to get this example to work?
There is nothing like start()
slot in QState
- but it exists in QStateMachine
.
I suppose you want to reimplement
virtual void onEntry ( QEvent * event )
virtual void onExit ( QEvent * event )
methods:
class MyState: public QState
{
Q_OBJECT
private:
QString _stateName;
public:
MyState(QString stateName, QState * parent = 0):QState(parent), _stateName(stateName){}
~MyState(){}
protected:
virtual void onEntry(QEvent * event)
{
qDebug() << _stateName << " start.";
}
virtual void onExit(QEvent * event)
{
qDebug() << _stateName << " stop.";
}
signals:
void finished();
//void exited();
};
which is working just fine.