QThread如何从自己的线程发送一个信号,并将enum作为QML中使用的参数?

QThread如何从自己的线程发送一个信号,并将enum作为QML中使用的参数?,qt,enums,qml,signals-slots,qthread,Qt,Enums,Qml,Signals Slots,Qthread,在下面的代码中,如果从主线程发出信号errorOccessed,则它可以正常工作。但是,如果它是从QThread线程发出的,则会失败,并出现以下错误: QObject::connect: Cannot queue arguments of type 'ErrorCode' (Make sure 'ErrorCode' is registered using qRegisterMetaType().) 是否有一种方法可以成功地从QThread线程发出信号?如果是,怎么做 MyClass.h #

在下面的代码中,如果从主线程发出信号
errorOccessed
,则它可以正常工作。但是,如果它是从
QThread
线程发出的,则会失败,并出现以下错误:

QObject::connect: Cannot queue arguments of type 'ErrorCode'
(Make sure 'ErrorCode' is registered using qRegisterMetaType().)
是否有一种方法可以成功地从
QThread
线程发出信号?如果是,怎么做

MyClass.h

#import <QThread>
#import <atomic>

class MyClass : public QThread
{
    Q_OBJECT

public:
    explicit MyClass(QObject *parent = Q_NULLPTR);
    virtual ~MyClass() override;

    enum ErrorCode {
        ErrorA,
        ErrorB,
        ErrorC
    };
    Q_ENUM(ErrorCode)

signals:
    void errorHappened(ErrorCode errorCode);

public slots:
    void mainThreadError();
    void otherThreadError();

private:
    std::atomic<bool> m_running;
    std::atomic<bool> m_signalStop;
    std::atomic<bool> m_signalError;

    void run() override;
    void stop();
};
main.cpp

#include "MyClass.h"

MyClass::MyClass(QObject *parent)
    : QThread(parent)
{
    start();
}

MyClass::~MyClass()
{
    stop();
}

void MyClass::mainThreadError()
{
    emit errorHappened(ErrorCode::ErrorA);
}

void MyClass::otherThreadError()
{
    m_signalError = true;
}

void MyClass::run()
{
    m_running = true;

    while (!m_signalStop) {
        if (m_signalError) {
            emit errorHappened(ErrorCode::ErrorA);
            m_signalError = false;
        }
        msleep(1);
    }

    m_running = false;
    m_signalStop = false;
}

void MyClass::stop()
{
    if (m_running) {
        m_signalStop = true;
        wait();
    }
}
#include <QGuiApplication>
#include <QQuickView>
#include "MyClass.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQuickView *view = new QQuickView();

    qmlRegisterType<MyClass>("MyClass", 1, 0, "MyClass");

    view->setSource((QUrl(QStringLiteral("qrc:/main.qml"))));
    view->create();
    view->show();

    return app.exec();
}
#include <QGuiApplication>
#include <QQuickView>
#include "MyClass.h"

static void registerTypes(){
    qRegisterMetaType<MyClass::ErrorCode>("ErrorCode");
    qmlRegisterType<MyClass>("MyClass", 1, 0, "MyClass");
}

Q_COREAPP_STARTUP_FUNCTION(registerTypes)

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView view;
    view.setSource((QUrl(QStringLiteral("qrc:/main.qml"))));
    view.show();
    return app.exec();
}
您的类型“ErrorCode”仅在线程中定义(不在主线程中)

  • 对于可以使用的用户定义类型(请阅读此)

    Q_DECLARE_元类型(ErrorCode)

  • 对参数使用标准类型(int、QMap、QString…)


  • qmlRegisterType使QObject(MyClass)类可以在QML中访问(Q_属性、Q_枚举、Q_信号、Q_插槽、Q_可调用等),但不允许在线程之间传输数据,在这种情况下,必须使用
    qRegisterMetaType(“ErrorCode”)

    main.cpp

    #include "MyClass.h"
    
    MyClass::MyClass(QObject *parent)
        : QThread(parent)
    {
        start();
    }
    
    MyClass::~MyClass()
    {
        stop();
    }
    
    void MyClass::mainThreadError()
    {
        emit errorHappened(ErrorCode::ErrorA);
    }
    
    void MyClass::otherThreadError()
    {
        m_signalError = true;
    }
    
    void MyClass::run()
    {
        m_running = true;
    
        while (!m_signalStop) {
            if (m_signalError) {
                emit errorHappened(ErrorCode::ErrorA);
                m_signalError = false;
            }
            msleep(1);
        }
    
        m_running = false;
        m_signalStop = false;
    }
    
    void MyClass::stop()
    {
        if (m_running) {
            m_signalStop = true;
            wait();
        }
    }
    
    #include <QGuiApplication>
    #include <QQuickView>
    #include "MyClass.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQuickView *view = new QQuickView();
    
        qmlRegisterType<MyClass>("MyClass", 1, 0, "MyClass");
    
        view->setSource((QUrl(QStringLiteral("qrc:/main.qml"))));
        view->create();
        view->show();
    
        return app.exec();
    }
    
    #include <QGuiApplication>
    #include <QQuickView>
    #include "MyClass.h"
    
    static void registerTypes(){
        qRegisterMetaType<MyClass::ErrorCode>("ErrorCode");
        qmlRegisterType<MyClass>("MyClass", 1, 0, "MyClass");
    }
    
    Q_COREAPP_STARTUP_FUNCTION(registerTypes)
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
        QQuickView view;
        view.setSource((QUrl(QStringLiteral("qrc:/main.qml"))));
        view.show();
        return app.exec();
    }
    #包括
    #包括
    #包括“MyClass.h”
    静态无效注册表类型(){
    qRegisterMetaType(“错误代码”);
    qmlRegisterType(“MyClass”,1,0,“MyClass”);
    }
    Q_COREAPP_启动功能(注册表类型)
    int main(int argc,char*argv[])
    {
    QGUI应用程序应用程序(argc、argv);
    QQuickView视图;
    view.setSource((QUrl(QStringLiteral(“qrc:/main.qml”)));
    view.show();
    返回app.exec();
    
    }
    您从哪里获得这些信息的?我从来没有在任何文件中读到过。我认为这与此无关。创建宏
    Q_ENUM
    是为了处理在其自身内声明/注册元类型。请注意,如果我导致调用
    MyClass::mainThreadError()
    ,则它可以正常工作。只有当信号从
    QThread
    线程触发时,才会出现问题,例如,导致调用
    MyClass::otherThreadError()
    。请注意qRegisterMetaType()!=qmlRegisterType()谢谢!你的开场白——这有没有记录在案?@PaulMasri Stone这并不明确,但可以从文件和错误中推断出来。