Qt状态机:如何将单个转换与多个状态关联?

4

问题

我目前正在使用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();
}

为什么不使用 addTransition 的其他重载版本 - Rostislav
因为我想通过子类化QSignalTransition来重写OnTransition。 - Vivek Maran
鉴于 QAbstractTransition 似乎总是只有一个源状态,我认为你需要找到另一种方法,比如将某些共享状态传递给你的 QSignalTransition 子类的多个实例。 - Rostislav
1个回答

3
您可以在状态进入时移动转换。
connect(m_state, &QState::entered, [m_state, m_tr]() -> void { m_state->addTransition(m_tr); });

或者只需使用父级状态来保留转换并将转换类型设置为internal。

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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接