- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试向 qstatemachine 添加一个带有字符串和枚举的属性,但是 machine.property() 的结果是空的。
QStatemachine m_machine;
idle->assignProperty(&m_machine, "state", Z_IDLE);
cool->assignProperty(&m_machine, "state", Z_COOL);
start_z->assignProperty(&m_machine, "state", Z_START);
QVariant st = m_machine->property("state");
QString s = st.toString();
我试图展示我的方法,看看它是否可行。
更新:
idle = new QState();
start_z = new QState();
lock = new QState();
connect(this, SIGNAL(machine_exec()), this, SLOT(idle_exec()));
connect(this, SIGNAL(machine_exec()), this, SLOT(start_z_exec()));
connect(this, SIGNAL(machine_exec()), this, SLOT(sample_exec()));
m_machine->addState(idle);
m_machine->addState(start_z);
m_machine->addState(lock);
idle->assignProperty(m_machine, "state", Z_IDLE);
cool->assignProperty(m_machine, "state", Z_COOL);
start_z->assignProperty(m_machine, "state", Z_START);
idle->addTransition(this, SIGNAL(machineToStart()), start_z);
cool->addTransition(this, SIGNAL(machineToMotDn()), motDn);
motDn->addTransition(this, SIGNAL(machineToFini()), fini);
void MeasController::idle_exec()
{
qDebug()<<"idle_exec";
emit machineToStart();
}
void MeasController::start_z_exec()
{
qDebug()<<"start_z_exec";
QVariant s = m_machine->property("state");
qDebug()<<"property value"<<s.toString();
if (m_machine->property("state") == Z_START) {
emit machineStartToSample();
}
}
最佳答案
属性仅在状态转换时分配,因此如果您在机器启动之前检查属性的值并且事件循环有机会运行,您将不会获得有效值。
此外,如果多次使用属性名称,您可能会犯错字。您应该为属性名称使用命名常量,而不是字符串文字——并且它们应该足够不同,这样随机拼写错误就会被捕获。 IE。 kStateA
和 kStateB
之类的属性名称可能过于相似 - 拼写错误会导致无声。
因此,我将代码更改为:
static const char kState[] = "state";
QStatemachine m_machine;
idle->assignProperty(&m_machine, kState, Z_IDLE);
cool->assignProperty(&m_machine, kState, Z_COOL);
start_z->assignProperty(&m_machine, kState, Z_START);
qDebug() << m_machine->property(kState).toString();
另请注意,这种单一当前状态的概念仅适用于您的机器是非分层的。由 QStateMachine
实现的通用 HSM 始终处于 set 状态,可从 configuration()
获得。大多数现实的机器应该是分层的,因此您的方法将行不通。
还不清楚 _exec
方法以及用于在状态之间转换的显式信号是否有任何用途。
下面是您可能会觉得有用的方法的完整示例。
首先,让我们从如何简洁地指定您的 MeasController
开始:
class MeasController : public QObject {
Q_OBJECT
QStateMachine m_machine{this};
NamedState
m_idle {"Idle", &m_machine},
m_start_z {"Start Z", &m_machine},
m_active_z{"Active Z", &m_machine},
m_downMove{"DownMove", &m_machine};
Transition
m_toStartZ{&m_idle, &m_start_z},
m_toDownMove{&m_active_z, &m_downMove};
Delay
m_d1{&m_start_z, &m_active_z, 1000},
m_d2{&m_downMove, &m_active_z, 2000};
QList<QState*> states() const { return m_machine.findChildren<QState*>(); }
public:
MeasController(QObject * parent = 0) : QObject(parent) {
for (auto state : states())
connect(state, &QState::entered, [state]{ qDebug() << state->objectName(); });
m_machine.setInitialState(&m_idle);
m_machine.start();
}
Q_SLOT void startZ() { m_toStartZ.trigger(); }
Q_SLOT void moveDown() { m_toDownMove.trigger(); }
};
这是状态机的完整规范。状态及其转换和其他行为作为 MeasController
的成员给出,因此很容易在一个地方找到。为了便于调试,在进入每个状态时都会提供调试输出。提供槽以从类外部触发行为,而无需暴露内部结构。
现在让我们看一下 NamedState
、Transition
和 Delay
类定义的习语。
命名状态习惯用法,类似于 Qt 3 的 QObject
在构造函数中取名,至少对调试很有用。如果你想分配状态的任何其他属性,你也可以在这个类中这样做。由于状态具有唯一的变量名称并且是父类的成员,因此不需要任何整数标识符:
// https://github.com/KubaO/stackoverflown/tree/master/questions/state-properties-36745219
#include <QtWidgets>
class NamedState : public QState { Q_OBJECT
public:
NamedState(const char * name, QStateMachine * parent) : QState(parent) {
setObjectName(QString::fromUtf8(name));
}
};
过渡类有助于提供一种简洁的方法来将状态机的结构指定为 Transition
实例的简单成员定义:
struct Transition : public QObject { Q_OBJECT
public:
Transition(QState * source, QState * destination) : QObject(source->machine()) {
source->addTransition(this, &Transition::trigger, destination);
}
Q_SIGNAL void trigger();
};
我确信您的状态机具有更复杂的行为,但通常它有助于将特定行为分解到它自己的类中。例如。假设您想要在延迟后发生的状态转换:
class Delay : public Transition { Q_OBJECT
int m_delay;
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev) {
if (m_timer.timerId() != ev->timerId()) return;
m_timer.stop();
trigger();
}
public:
Delay(QState * s, QState * d, int ms) : Transition(s, d), m_delay(ms) {
connect(s, &QState::entered, this, [this]{ m_timer.start(m_delay, this);});
}
};
最后,我们可以提供一个简单的 UI 来测试和可视化机器的行为。调试输出在 QPlainTextEdit
中复制以便于使用。
int main(int argc, char ** argv) {
QApplication app{argc, argv};
MeasController ctl;
QWidget w;
QGridLayout layout{&w};
QPushButton start{"Start"};
QPushButton moveDown{"Move Down"};
QPlainTextEdit log;
log.setReadOnly(true);
layout.addWidget(&start, 0, 0);
layout.addWidget(&moveDown, 0, 1);
layout.addWidget(&log, 1, 0, 1, 2);
QObject::connect(&start, &QPushButton::clicked, &ctl, &MeasController::startZ);
QObject::connect(&moveDown, &QPushButton::clicked, &ctl, &MeasController::moveDown);
static QtMessageHandler handler = qInstallMessageHandler(
+[](QtMsgType t, const QMessageLogContext& c, const QString & msg){
static QPointer<QPlainTextEdit> log{[]{
for (auto w : qApp->topLevelWidgets())
for (auto log : w->findChildren<QPlainTextEdit*>()) return log;
Q_ASSERT(false);
}()};
if (log) log->appendPlainText(msg);
handler(t, c, msg);
});
w.show();
return app.exec();
}
#include "main.moc"
完整示例到此结束。 This是一个有点类似风格的更长的例子。
关于c++ - QState::assignProperty 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36745219/
我在 QGraphicsView 上显示了一张图片,我试图使用状态机让它移动。单击图像后,我希望它向下移动 200 像素,然后再向右移动 200 像素。这是我到目前为止的代码,但问题是图像不是按需要以
我有一个类,包含一个QStateMachine。它还有几个 QState*。 private: QStateMachine m_machine; QState* m_state1 QState* m_
我正在尝试向 qstatemachine 添加一个带有字符串和枚举的属性,但是 machine.property() 的结果是空的。 QStatemachine m_machine; idle->as
以下代码由于内存损坏而导致崩溃。我假设这是因为 delete pTestStateMachine 试图删除未在堆中分配的内存。对吗? 如果是这样,是否意味着 QStateMachine::addSta
我正在尝试向 QStateMachine 添加一个状态,它给出了一个警告 [20.04 13:31:02 W] QStateMachine::addState: state has already b
有一个状态机(称为外部)。这台机器有两个状态——第一个和最后一个。第一个状态是自定义实现的。在第一个状态中创建了另一个状态机(称为内部状态机),在本例中它什么也不做。 具有两个状态的外部状态机:
我是一名优秀的程序员,十分优秀!