2015-10-18 17 views
3

ВопросQt состояние машины: Как связать один переход с несколькими состояниями

Сейчас я работаю над приложением, используя структуру государственной машины Qt, моя цель состоит в том, чтобы связать один переход с несколькими состояниями источника. Обоснованием для этого является сигнал, вызывающий переход, не зависит от исходного состояния, поэтому вместо нескольких переходов (по одному для каждого исходного состояния) я думал, что было бы лучше иметь его. Я столкнулся с проблемами, связанными с рассмотрением вышеизложенного с помощью Qt. Подробности приведены ниже с помощью тестового состояния. (Ниже упоминается гипотетическая машина состояний, но я могу также привести примеры реальных примеров для такого использования). Просьба предложить несколько эффективных способов для достижения указанной цели.

Фрагмент кода, где проблема лежит

m_s1.addTransition(&m_Trans); // Adding transition to state S1 
m_s2.addTransition(&m_Trans); // Adding the same transition to state S2 
           // As per Qt docs, it seems the ownership of thr transition will be transferred to s2 which is what is causing the problem. 

enter image description here

CState.hpp

class CState: public QState 
{ 

public: 

    /** Constructor */ 
    CState(std::string a_pStateName) 
     :QState(nullptr), 
     m_pStateName(a_pStateName) 
    { 

    } 

    /** Overriding on entry */ 
    virtual void onEntry(QEvent *a_pEvent) Q_DECL_OVERRIDE 
    { 
     (void) a_pEvent; 
     printf("State entry %s\n",m_pStateName.c_str()); 
    } 

    ~CState() {} 
    CState() {} 
private: 
    std::string m_pStateName; 
}; 

CTestMachine.hpp

class CTestStateMachine: public QObject 
{ 
    Q_OBJECT 

public: 
    CTestStateMachine(); 
    ~CTestStateMachine() {}; 

private: 
    QSignalTransition  m_Trans; 
    CState     m_s1; 
    CState     m_s2; 
    CState     m_s3; 
    QStateMachine   m_TestMachine; 
    QTimer     m_Timer; 

signals: 
    void SourceIndependentSignal(); 

public slots: 
    void TimetoInvokeTrans(); 


}; 

CTestMachine.cpp

#include <stdio.h> 
#include <iostream> 
#include <string> 
using namespace std; 

#include <QObject> 
#include <QCoreApplication> 
#include <QStateMachine> 
#include <QState> 
#include <QSignalTransition> 
#include <QTimer> 

#include "CState.hpp" 
#include "CTestStateMachine.hpp" 

void CTestStateMachine::TimetoInvokeTrans() 
{ 
    printf("Emitting source independent signal\n"); 
    emit SourceIndependentSignal(); 
} 

CTestStateMachine::CTestStateMachine(): 
    m_Trans(this, SIGNAL(SourceIndependentSignal())), 
    m_s1("s1"), 
    m_s2("s2"), 
    m_s3("s3") 
{ 
    /* Setup state machine */ 
    m_Trans.setTargetState(&m_s3); 
    m_s1.addTransition(&m_Trans); 
    m_s2.addTransition(&m_Trans); 
    m_TestMachine.addState(&m_s1); 
    m_TestMachine.addState(&m_s2); 
    m_TestMachine.addState(&m_s3); 
    m_TestMachine.setInitialState(&m_s1); 
    m_TestMachine.start(); 
    printf("Started state machine\n"); 

    /* Trigger timer to make transitions */ 
    connect(&m_Timer, SIGNAL(timeout()), this, SLOT(TimetoInvokeTrans())); 
    m_Timer.start(1000); 
} 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    CTestStateMachine TestMachine; 
    return a.exec(); 
} 
+0

Почему бы не использовать другие [перегрузки] (http://doc.qt.io/qt-5/qstate.html#addTransition-1) от 'addTransition'? – Rostislav

+0

Поскольку я хотел бы переопределить 'OnTransition' путем подкласса' QSignalTransition', –

+0

Ну, учитывая, что 'QAbstractTransition', кажется, всегда имеет только одно исходное состояние, я бы сказал, что вам нужно будет найти другой подход, например, общего состояния для нескольких экземпляров вашего подкласса 'QSignalTransition'. – Rostislav

ответ

3

Вы можете переместить переход на государственную запись.

connect(m_state, &QState::entered, [m_state, m_tr]() -> void { m_state->addTransition(m_tr); }); 

Или просто иметь родительское состояние, чтобы сохранить переход и установить тип перехода на внутренний.

QState *s = new QState(m_stateMachine); 
QState *s1 = new QState(s); 
QState *s2 = new QState(s); 
QState *s3 = new QState(s); 
QSignalTransition *sTr = new QSignalTransition(sender, SIGNAL(foobar), s); 
sTr->setTargetState(s3); 
sTr->setTransitionType(QAbstractTransition::InternalTransition);