c++qtruntime-errorqstatemachine

Unable to start state and transition between states: receiving various errors


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?


Solution

  • 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.