2015-09-16 66 views
2

有一個狀態機(稱爲外部)。這臺機器有兩個狀態 - 第一個和最後一個。第一個狀態是自定義的。在第一個狀態中,創建了另一個狀態機(稱爲內部狀態機),在這個例子中什麼都不做。爲什麼在構造函數中使用此指針的QState子類中嵌套的QStateMachine會導致外部狀態機無法進行轉換?

外狀態機具有兩種狀態:

#include <QDebug> 
    #include <QCoreApplication> 
    #include <QTimer> 
    #include <custom_outer_state.hpp> 
    #include <QFinalState> 
    #include "a.hpp" 

    class Functor 
    { 
    public: 
    void operator()() 
    { 
     // just emits a signal 
     TestObject outerTestObject; 

     // create outer state machine with all states 
     QStateMachine outerStateMachine; 
     CustomOuterState *state1 = new CustomOuterState(); 
     QFinalState *state2 = new QFinalState(); 
     state1->addTransition(&outerTestObject, SIGNAL(testObjectSignal()), state2); 
     outerStateMachine.addState(state1); 
     outerStateMachine.addState(state2); 
     outerStateMachine.setInitialState(state1); 
     outerStateMachine.start(); 

     // process state machine transitions 
     QCoreApplication::processEvents(); 
     qDebug() << &outerStateMachine << ": Outer state machine first state " << outerStateMachine.configuration(); 
     outerTestObject.testObjectSignal(); 
     QCoreApplication::processEvents(); 
     qDebug() << &outerStateMachine << ": Outer state machine second state " << outerStateMachine.configuration(); 
    } 
    }; 

    int main(int argc, char *argv[]) 
    { 
    QCoreApplication app(argc, argv); 
    QTimer::singleShot(0, Functor()); 
    return QCoreApplication::exec(); 
    } 

和自定義狀態:

#ifndef CUSTOM_OUTER_STATE_H 
    #define CUSTOM_OUTER_STATE_H 

    #include <QState> 
    #include <QStateMachine> 

    class CustomOuterState : public QState 
    { 
    Q_OBJECT 
    public: 
    virtual void onEntry(QEvent * event) 
    { 
     // create inner state machine 
     machine = new QStateMachine(); 
     /* 
     * some operations with the machine 
     */ 
    } 
    private: 
    QStateMachine* machine; 
    }; 

    #endif 

和試驗對象,它只是發出了一個信號:

#ifndef A_H 
    #define A_H 

    #include <QObject> 

    class TestObject : public QObject 
    { 
    Q_OBJECT 
    signals: 
    void testObjectSignal(); 
    }; 

    #endif 

所以這個代碼工作預計 - 外部狀態機從第一個狀態變爲最終狀態:

QStateMachine(0x7fffc00f0a20) : Outer state machine first state QSet(CustomOuterState(0xe0a380)) 
    QStateMachine(0x7fffc00f0a20) : Outer state machine second state QSet(QFinalState(0xe0a460)) 

但隨着定製狀態內的變化不大 - 傳遞this(這是QState子類)的內部狀態機的構造

-  machine = new QStateMachine(); 
    +  machine = new QStateMachine(this); 

結果可知,狀態機沒有按」 t想要轉換 - 雖然發送了轉換信號,但它仍保持第一狀態

QStateMachine(0x7fff219edcb0) : Outer state machine first state QSet(CustomOuterState(0x1fc4380)) 
    QStateMachine(0x7fff219edcb0) : Outer state machine second state QSet(CustomOuterState(0x1fc4380)) 

解決方案很簡單 - 只需刪除內部狀態機,一切正常。但問題是爲什麼壞事發生。

那麼,爲什麼加入this這是QState狀態機的構造函數結果的子類,以便狀態機並不想轉型做?

+1

問題可能是因爲QStateMachine從QState類中觸發。在consturctor中的QState類可以接受父狀態,因此,「this」指針是QStateMachine的父狀態。 – Milovidov

回答

3

您試圖從狀態的事件處理程序修改狀態機的狀態圖。這不受狀態機支持。由於QStateMachine是-a QState,通過將其添加爲小孩,您正在修改狀態圖。

onEntry被調用時,狀態圖如下所示:
statechart before
onEntry,將其更改爲類似下面。 machine不是初始狀態,它只是一個懸而未決的狀態。即使它沒有懸掛,它仍然無法使用,因爲它是在狀態轉換期間添加的。
statechart after

由於QStateMachineQState,當你把它的狀態的直接子就變成這種狀態的子狀態。如果您只想將狀態用作狀態機的容器,則可以在父狀態和狀態之間插入一箇中間狀態的非狀態對象。

// https://github.com/KubaO/stackoverflown/tree/master/questions/statemachine-nested-32619103 
#include <QtCore> 

struct OuterState : QState 
{ 
    QStateMachine * machine { nullptr }; 
    virtual void onEntry(QEvent *) Q_DECL_OVERRIDE 
    { 
     // through an intervening container 
     auto container = new QObject(this); 
     machine = new QStateMachine(container); 
    } 
    OuterState(QState * parent = 0) : QState(parent) {} 
}; 

最後,調用processEvents的僞同步代碼是不必要的。您可以在輸入狀態時執行操作等。回想一下,由於信號是一個可調用的方法,就像插槽一樣,您可以將信號連接到信號。事實上,既然你想實現的是無條件的過渡,那麼你也可以使用它。

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    // create outer state machine with all states 
    QStateMachine outerStateMachine; 
    OuterState state1 { &outerStateMachine }; 
    QFinalState state2 { &outerStateMachine }; 
    state1.addTransition(&state2); 
    outerStateMachine.setInitialState(&state1); 
    outerStateMachine.start(); 

    a.connect(&state1, &QState::entered, []{ qDebug() << "state1 entered"; }); 
    a.connect(&state2, &QState::entered, []{ qDebug() << "state2 entered"; }); 
    a.connect(&state2, &QState::entered, qApp, &QCoreApplication::quit); 
    return a.exec(); 
} 

以上是或多或少的,自包含的測試用例應該是什麼樣子:單個文件,沒有絨毛和冗長,從這個問題手頭減損。

相關問題