使用QCoreApplication时,QStateMachine未正确执行

QStateMachine not executing correctly when using QCoreApplication

本文关键字:执行 QStateMachine QCoreApplication 使用      更新时间:2023-10-16

我正试图在控制台应用程序中实现一个简单的状态机。本应触发状态转换的信号正在发出,然而,状态机并没有对这些信号做出反应。

当在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!";
}

解决了我的问题。该问题是由while循环无限引起的。只有在Run函数结束后才能调用slot,这显然从未发生过。

这是一个有效的解决方案。对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();
}