我正在尝试在控制台应用程序中实现一个简单的状态机。正在发出应该触发状态转换的信号,但状态机不会对这些信号作出反应。
这个状态机在QApplication(即GUI应用程序)中运行时运行良好,但是我想开发一个控制台应用程序。我怀疑我实现事件循环的方式存在问题,因为QStateMachine没有发出started()信号。
执行应用程序以使状态机正常运行的正确方法是什么?
main.cpp中:
#include <QCoreApplication>
#include "test.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
QMetaObject::invokeMethod( &test, "Run", Qt::QueuedConnection );
return a.exec();
}
test.h:
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QStateMachine>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0) : QObject(parent) {}
public slots:
void Run();
signals:
void stateChanged();
void debugSignal();
private:
void buildStateMachine();
QStateMachine machine;
private slots:
void runS1();
void runS2();
void runS3();
void debugSlot();
};
#endif // TEST_H
TEST.CPP:
#include "test.h"
#include <QDebug>
void Test::Run()
{
buildStateMachine();
QTextStream qin(stdin);
while (true)
{
QString line = qin.readLine();
qDebug() << "line: " << line;
if (line == "A")
{
qDebug() << "emit stateChanged signal";
emit stateChanged();
}
else if (line == "B")
{
qDebug() << "emit debugSignal";
emit debugSignal();
}
}
}
void Test::buildStateMachine()
{
connect(&machine, SIGNAL(started()), this, SLOT(debugSlot())); // doesn't seem to get triggered... (why is machine not starting?)
connect(this, SIGNAL(debugSignal()), this, SLOT(debugSlot())); // works as expected
QState *s1 = new QState(&machine);
QState *s2 = new QState(&machine);
QState *s3 = new QState(&machine);
s1->addTransition(this, SIGNAL(stateChanged()), s2);
s2->addTransition(this, SIGNAL(stateChanged()), s3);
s3->addTransition(this, SIGNAL(stateChanged()), s1);
connect(s1, SIGNAL(entered()), this, SLOT(runS1())); // these are never triggered
connect(s2, SIGNAL(entered()), this, SLOT(runS2()));
connect(s3, SIGNAL(entered()), this, SLOT(runS3()));
s1->assignProperty(&machine, "state", 1);
s2->assignProperty(&machine, "state", 2);
s3->assignProperty(&machine, "state", 3);
machine.setInitialState(s1);
machine.start();
}
void Test::runS1()
{
qDebug() << "entered state S1";
}
void Test::runS2()
{
qDebug() << "entered state S2";
}
void Test::runS3()
{
qDebug() << "entered state S3";
}
void Test::debugSlot()
{
qDebug() << "slot was triggered!";
}
答案 0 :(得分:0)
解决了我的问题。问题是由无限循环引起的。只有在Run函数结束后才能调用插槽,这显然永远不会发生。
这是一个有效的解决方案。 Qt 5样式信号和插槽语法的更改是可选的。如果main.cpp与上述问题中显示的版本保持原样,则应用程序将无法正常退出。
main.cpp中:
#include <QCoreApplication>
#include <QTimer>
#include "test.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
QObject::connect(&test, &Test::finished, &a, &QCoreApplication::quit, Qt::QueuedConnection);
QTimer::singleShot(0, &test, &Test::Run);
return a.exec();
}
test.h:
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QStateMachine>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0);
signals:
void next_state();
void finished();
private:
void buildStateMachine();
QStateMachine machine;
public slots:
void Run();
void runS1();
void runS2();
void runS3();
void debugSlot();
};
#endif // TEST_H
TEST.CPP:
#include "test.h"
#include <iostream>
#include <QTextStream>
Test::Test(QObject * parent) : QObject(parent)
{
buildStateMachine();
}
void Test::Run()
{
QTextStream qin(stdin);
std::cout << "line: ";
QString line = qin.readLine();
if (line == "A")
{
std::cout << "emit stateChanged signal" << std::endl;
emit next_state();
}
else if (line == "q")
{
emit finished();
}
else
{
Run();
}
}
void Test::buildStateMachine()
{
QState *s1 = new QState(&machine);
QState *s2 = new QState(&machine);
QState *s3 = new QState(&machine);
s1->addTransition(this, SIGNAL(next_state()), s2);
s2->addTransition(this, SIGNAL(next_state()), s3);
s3->addTransition(this, SIGNAL(next_state()), s1);
connect(s1, &QState::entered, this, &Test::runS1);
connect(s2, &QState::entered, this, &Test::runS2);
connect(s3, &QState::entered, this, &Test::runS3);
machine.setInitialState(s1);
machine.start();
}
void Test::runS1()
{
std::cout << "entered state S1" << std::endl;
Run();
}
void Test::runS2()
{
std::cout << "entered state S2" << std::endl;
Run();
}
void Test::runS3()
{
std::cout << "entered state S3" << std::endl;
Run();
}
void Test::debugSlot()
{
std::cout << "debug slot was triggered!" << std::endl;
Run();
}