2015-03-22 2 views
0

Я пытаюсь реализовать простой конечный автомат в консольном приложении. Сигналы, которые должны инициировать переходы состояния, испускаются, однако конечный автомат не реагирует на эти сигналы.QStateMachine не работает правильно при использовании QCoreApplication

Этот конечный автомат отлично работает при работе в QApplication (то есть графическом приложении), однако я хочу разработать консольное приложение. Я подозреваю, что проблема в том, как я реализовал цикл событий, поскольку QStateMachine не испускает сигнал start().

Каков правильный способ выполнения приложения для правильной работы конечного автомата?

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

решить мою проблему. Проблема была вызвана бесконечным циклом while. Слот может вызываться только после завершения функции 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(); 
} 
Смежные вопросы