子类化和修改 QStateMachine
Subclassing and modifying QStateMachine
假设我有一群 运行 一个 QStateMachine
的机器人。这些机器人的所有状态机都具有相同的基本结构:
- 声明:
- 睡觉
- 搜索
- 摧毁
- Return
- 转换(
from
-> to
signal
:
- 睡眠 -> 在 "next"
上搜索
- 搜索 -> 在 "next"
上销毁
- 销毁 -> 在 "next"
上搜索
- 在 "back"
上摧毁 -> Return
- 在 "back"
上搜索 -> Return
- Return -> 在 "next"
上搜索
- Return -> 在 "back"
上睡觉
// base.h
#include <QObject>
#include <QState>
#include <QStateMachine>
class Base : public QObject
{
Q_OBJECT
public:
Base(QObject* parent = 0);
~Base();
signals:
void next();
void back();
private:
QStateMachine m_machine;
QState* m_sleep;
QState* m_search;
QState* m_destroy;
QState* m_return;
};
// base.cpp
Base::Base(QObject* parent) : QObject(parent)
{
m_sleep = new QState(&m_machine);
m_search = new QState(&m_machine);
m_destroy = new QState(&m_machine);
m_return = new QState(&m_machine);
m_machine.setInitialState(m_sleep);
m_sleep->addTransition(this, &Base::next, m_search);
m_search->addTransition(this, &Base::next, m_destroy);
m_search->addTransition(this, &Base::back, m_return);
m_destroy->addTransition(this, &Base::next, m_search);
m_destroy->addTransition(this, &Base::back, m_return);
m_return->addTransition(this, &Base::next, m_search);
m_return->addTransition(this, &Base::back, m_sleep);
m_machine.start();
}
现在我想要一个可能更具体一点的机器人。假设他在破坏过程中更加详细,具有几个子状态,例如dismantel -> sprayWithAcid -> blowUp -> desintegrate
,他在每个 next
-信号时继续前进,或者他在 back
-信号时继续 return
。
如前所述,我的计划是将它们作为子状态添加到状态 destroy
,但由于信号 next
不仅会继续子状态机直到完成,还会离开父状态.
我怎样才能避免这种情况? 或者有其他类似的好方法吗?
我明白了。
诀窍是显式创建转换,将它们作为 class 的成员。您可以这样设置它们:
m_sleepSearch = new QSignalTransition(this, &Base::next, m_sleep);
m_searchDestroy = new QSignalTransition(this, &Base::next, m_search);
m_searchReturn = new QSignalTransition(this, &Base::back, m_search);
m_destroySearch = new QSignalTransition(this, &Base::next, m_destroy);
m_destroyReturn = new QSignalTransition(this, &Base::back, m_destroy);
m_returnSearch = new QSignalTransition(this, &Base::next, m_return);
m_returnSleep = new QSignalTransition(this, &Base::back, m_return);
m_sleepSearch->setTargetState(m_search);
m_searchDestroy->setTargetState(m_destroy);
m_searchReturn->setTargetState(m_return);
m_destroySearch->setTargetState(m_search);
m_destroyReturn->setTargetState(m_return);
m_returnSearch->setTargetState(m_search);
m_returnSleep->setTargetState(m_sleep);
我首先出错的是 QSignalTransition(sender, signal, source_state)
构造函数的参数错误,因为它与 ->addTransition(sender, signal, target_state)
的语法太相似了,所以我混淆了 source
和 target
.
像这样创建它们之后,当子class这个对象时,重新路由或禁用其中一些转换应该很容易。
假设我有一群 运行 一个 QStateMachine
的机器人。这些机器人的所有状态机都具有相同的基本结构:
- 声明:
- 睡觉
- 搜索
- 摧毁
- Return
- 转换(
from
->to
signal
:- 睡眠 -> 在 "next" 上搜索
- 搜索 -> 在 "next" 上销毁
- 销毁 -> 在 "next" 上搜索
- 在 "back" 上摧毁 -> Return
- 在 "back" 上搜索 -> Return
- Return -> 在 "next" 上搜索
- Return -> 在 "back" 上睡觉
// base.h
#include <QObject>
#include <QState>
#include <QStateMachine>
class Base : public QObject
{
Q_OBJECT
public:
Base(QObject* parent = 0);
~Base();
signals:
void next();
void back();
private:
QStateMachine m_machine;
QState* m_sleep;
QState* m_search;
QState* m_destroy;
QState* m_return;
};
// base.cpp
Base::Base(QObject* parent) : QObject(parent)
{
m_sleep = new QState(&m_machine);
m_search = new QState(&m_machine);
m_destroy = new QState(&m_machine);
m_return = new QState(&m_machine);
m_machine.setInitialState(m_sleep);
m_sleep->addTransition(this, &Base::next, m_search);
m_search->addTransition(this, &Base::next, m_destroy);
m_search->addTransition(this, &Base::back, m_return);
m_destroy->addTransition(this, &Base::next, m_search);
m_destroy->addTransition(this, &Base::back, m_return);
m_return->addTransition(this, &Base::next, m_search);
m_return->addTransition(this, &Base::back, m_sleep);
m_machine.start();
}
现在我想要一个可能更具体一点的机器人。假设他在破坏过程中更加详细,具有几个子状态,例如dismantel -> sprayWithAcid -> blowUp -> desintegrate
,他在每个 next
-信号时继续前进,或者他在 back
-信号时继续 return
。
如前所述,我的计划是将它们作为子状态添加到状态 destroy
,但由于信号 next
不仅会继续子状态机直到完成,还会离开父状态.
我怎样才能避免这种情况? 或者有其他类似的好方法吗?
我明白了。
诀窍是显式创建转换,将它们作为 class 的成员。您可以这样设置它们:
m_sleepSearch = new QSignalTransition(this, &Base::next, m_sleep);
m_searchDestroy = new QSignalTransition(this, &Base::next, m_search);
m_searchReturn = new QSignalTransition(this, &Base::back, m_search);
m_destroySearch = new QSignalTransition(this, &Base::next, m_destroy);
m_destroyReturn = new QSignalTransition(this, &Base::back, m_destroy);
m_returnSearch = new QSignalTransition(this, &Base::next, m_return);
m_returnSleep = new QSignalTransition(this, &Base::back, m_return);
m_sleepSearch->setTargetState(m_search);
m_searchDestroy->setTargetState(m_destroy);
m_searchReturn->setTargetState(m_return);
m_destroySearch->setTargetState(m_search);
m_destroyReturn->setTargetState(m_return);
m_returnSearch->setTargetState(m_search);
m_returnSleep->setTargetState(m_sleep);
我首先出错的是 QSignalTransition(sender, signal, source_state)
构造函数的参数错误,因为它与 ->addTransition(sender, signal, target_state)
的语法太相似了,所以我混淆了 source
和 target
.
像这样创建它们之后,当子class这个对象时,重新路由或禁用其中一些转换应该很容易。