C++ Qt状态机:如何将单个转换与多个状态关联
问题 我目前正在使用Qt状态机框架开发一个应用程序,我的目标是将单个转换与多个源状态关联起来。这样做的基本原理是导致转换的信号独立于源状态,因此我认为最好有一个转换,而不是多个转换(每个源状态一个)。我在通过Qt实现上述功能时遇到了一些问题。下面用一个测试状态机演示了详细信息。(下面提到的是一个假设的状态机,但我也可以给出一些这样一个用例的真实例子)。请提出一些实现上述目标的有效方法 问题所在的代码段C++ Qt状态机:如何将单个转换与多个状态关联,c++,qt,state-machine,qstatemachine,C++,Qt,State Machine,Qstatemachine,问题 我目前正在使用Qt状态机框架开发一个应用程序,我的目标是将单个转换与多个源状态关联起来。这样做的基本原理是导致转换的信号独立于源状态,因此我认为最好有一个转换,而不是多个转换(每个源状态一个)。我在通过Qt实现上述功能时遇到了一些问题。下面用一个测试状态机演示了详细信息。(下面提到的是一个假设的状态机,但我也可以给出一些这样一个用例的真实例子)。请提出一些实现上述目标的有效方法 问题所在的代码段 m_s1.addTransition(&m_Trans); // Adding tra
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.
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;
};
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();
};
#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();
}
CTestMachine.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;
};
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();
};
#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();
}
CTestMachine.cpp
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;
};
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();
};
#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();
}
#包括
#包括
#包括
使用名称空间std;
#包括
#包括
#包括
#包括
#包括
#包括
#包括“CState.hpp”
#包括“CTestStateMachine.hpp”
void CTestStateMachine::TimetoInvokeTrans()
{
printf(“发射源独立信号”);
发射SourceIndependentSignal();
}
CTestStateMachine::CTestStateMachine():
m_Trans(此,信号(SourceIndependentSignal()),
m_s1(“s1”),
m_s2(“s2”),
m_s3(“s3”)
{
/*设置状态机*/
m_Trans.setTargetState(&m_s3);
m_s1.添加转换(&m_Trans);
m_s2.添加转换(&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(“已启动状态机\n”);
/*触发计时器进行转换*/
连接(&m_定时器,信号(timeout()),此,插槽(TimetoInvokeTrans());
m_定时器启动(1000);
}
int main(int argc,char*argv[])
{
qcorea应用程序(argc、argv);
CTEStStateMetest测试机;
返回a.exec();
}
您可以在状态输入时移动转换
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);
为什么不使用另一个
addTransition
?因为我想通过子类化QSignalTransition
来覆盖OnTransition
,好吧,鉴于QAbstractTransition
似乎总是只有一个源状态,我想说你必须找到一种不同的方法,例如,将一些共享状态传递给QSignalTransition
子类的多个实例。