使用QCoreApplication时,QStateMachine无法正确执行

时间:2015-03-22 08:46:22

标签: c++ qt

我正在尝试在控制台应用程序中实现一个简单的状态机。正在发出应该触发状态转换的信号,但状态机不会对这些信号作出反应。

这个状态机在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!";
}

1 个答案:

答案 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();
}