【问题标题】:How to use enums in Qt signals and slots如何在 Qt 信号和槽中使用枚举
【发布时间】:2012-09-11 11:29:04
【问题描述】:

在信号中使用enum 类型时遇到了一些问题。基本上我有两个类,一个状态机和一个处理状态机的线程。当状态改变时,我想发送一个带有新状态的信号。我还想使用enum 来表示状态。在我的完整代码中,状态机是在一个单独的共享库中实现的,但下面的代码给出了完全相同的错误。

当我运行代码时,我得到以下行为:

kotte@EMO-Ubuntu:sigenum $ ./sigenum 
Object::connect: No such slot MyThread::onNewState(state)
Test signal 
Test signal 
...

我的示例代码中有四个文件:statemachine.hstatemachine.cppmain.hmain.cpp。 main 函数简单地启动线程,然后线程创建StateMachine 的实例并处理来自StateMachine 的信号。我对 Qt 很陌生,所以当我意识到你必须用Q_ENUMS 括起枚举并将其注册到类型系统时,我有点困惑。所以我完全有可能犯了一些菜鸟的错误

下面的代码有点长,但我希望它尽可能与我的真实代码相似。

statemachine.h 看起来像:

// statemachine.h
#ifndef _STATEMACHINE_H
#define _STATEMACHINE_H

#include <QtCore>

class StateMachine : public QObject
{
    Q_OBJECT
    Q_ENUMS(state)

public:
    enum state {S0, S1, S2};

    void setState(state newState);

signals:
    void stateChanged(state newState);
    void testSignal(void);
};

Q_DECLARE_METATYPE(StateMachine::state);

#endif

并且实现为:

// statemachine.cpp
#include <QtCore>

#include "statemachine.h"

void StateMachine::setState(state newState)
{
    emit stateChanged(newState);
    emit testSignal();
}

线程定义为

// main.h
#ifndef _MAIN_H
#define _MAIN_H

#include <QtCore>

#include "statemachine.h"

class MyThread : public QThread
{
    Q_OBJECT

private:
    void run(void);

private slots:
    void onNewState(StateMachine::state);
    void onTestSignal(void);

private:
    StateMachine *myStateMachine;
};

#endif

并且实现如下:

// main.cpp
#include <QtCore>
#include <QApplication>

#include "statemachine.h"
#include "main.h"

void MyThread::run()
{
    myStateMachine = new StateMachine();

    qRegisterMetaType<StateMachine::state>("state");

    // This does not work
    connect(myStateMachine, SIGNAL(stateChanged(state)),
            this, SLOT(onNewState(state)));

    // But this does...
    connect(myStateMachine, SIGNAL(testSignal()),
            this, SLOT(onTestSignal()));

    forever {
        // ...
        myStateMachine->setState(StateMachine::S0);
    }
}

void MyThread::onTestSignal()
{
    qDebug() << "Test signal";
}

void MyThread::onNewState(StateMachine::state newState)
{
    qDebug() << "New state is:" << newState;
}

【问题讨论】:

    标签: c++ qt enums


    【解决方案1】:

    通过在任何地方使用完全限定的名称,我得到了它的工作

    如果我将stateChanged() 的声明更改为

    signals:
        void stateChanged(StateMachine::state newState);
    

    并将类型注册到

    qRegisterMetaType<StateMachine::state>("StateMachine::state");
    

    并且还在connect 语句中使用此名称

    connect(myStateMachine, SIGNAL(stateChanged(StateMachine::state)),
            this, SLOT(onNewState(StateMachine::state)));
    

    如果没有 drescherjm 的帮助,就无法解决这个问题,谢谢 :-)

    【讨论】:

    • 为了记录,这解决问题的原因是元对象系统正在根据(标准化)字符串比较来决定信号/槽的兼容性。它不“知道”StateMachine::statestate 在此上下文中指的是同一类型。
    • 我不需要使用 Qt 4.8 的 qRegisterMetaType,只是到处都是完全限定的名称。
    • 得到了一个类似的例子,无需显式调用qRegisterMetaType(),只需从Q_DECLARE_METATYPE(StateMachine::state)行中删除分号
    【解决方案2】:

    我相信以下状态未在您的 MyThread 类中定义。

    使用下面的

    连接(myStateMachine,信号(stateChanged(StateMachine::state)), 这个,SLOT(onNewState(StateMachine::state)));

    编辑:

    也许这会起作用

    连接(myStateMachine,信号(stateChanged(状态)), 这个,SLOT(onNewState(StateMachine::state)));

    【讨论】:

    • 然后我得到No such signal StateMachine::stateChanged(StateMachine::state)
    • 您是否尝试过在 MyThread 界面中使用 typedef。我的意思是 typedef StateMachine::state state;
    • 始终在信号/槽声明(在标头中)中使用完整签名。
    【解决方案3】:

    您应该摆脱SIGNALSLOT,因为Qt 可以在编译时检测到不匹配。您还可以通过使用Q_ENUM 而不是Q_ENUMS 来避免使用Q_DECLARE_METATYPEqRegisterMetaType() - 这是在Qt 5.5 中引入的,最后enum classenum 的强类型版本:

    // statemachine.h
    #ifndef _STATEMACHINE_H
    #define _STATEMACHINE_H
    
    #include <QtCore>
    
    class StateMachine : public QObject
    {
        Q_OBJECT
        Q_ENUM(state)
    
    public:
        enum class state {S0, S1, S2};
    
        void setState(state newState);
    
    signals:
        void stateChanged(state newState);
        void testSignal(void);
    };
    
    #endif
    
    // main.cpp
    #include <QtCore>
    #include <QApplication>
    
    #include "statemachine.h"
    #include "main.h"
    
    void MyThread::run()
    {
        myStateMachine = new StateMachine();
    
        connect(myStateMachine, &StateMachine::stateChanged, this, &MyThread::NewState);
    
        connect(myStateMachine, &StateMachine::testSignal, this, &MyThread::onTestSignal);
    
        forever {
            // ...
            myStateMachine->setState(StateMachine::S0);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      相关资源
      最近更新 更多