Как QThread может посылать сигнал из своего собственного потока с перечислением в качестве аргумента для потребления в QML? - PullRequest
1 голос
/ 20 января 2020

В следующем коде, если сигнал errorHappened излучается из основного потока, он работает без проблем. Однако, если он излучается из потока 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();
};

MyClass . 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();
    }
}

main. cpp

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

main.qml

import QtQuick 2.12
import QtQuick.Controls 2.5
import MyClass 1.0

Rectangle {
    id: root

    width: 800
    height: 600
    focus: true

    MyClass {
        id: tester
        onErrorHappened: {
            var s
            switch (errorCode) {
            case MyClass.ErrorA:
                s = "Error A happened"
                break
            }
            console.log(s)
        }
    }

    Row {
        spacing: 30

        Button {
            id: mainThreadButton

            enabled: !tester.testRunning
            text: "Test on main thread"
            onClicked: tester.mainThreadError()
        }

        Button {
            id: otherThreadButton

            enabled: !tester.testRunning
            text: "Test on other thread"
            onClicked: tester.otherThreadError()
        }
    }
}

Ответы [ 2 ]

1 голос
/ 12 февраля 2020

qmlRegisterType делает класс QObject (MyClass) доступным в QML (Q_PROPERTY, Q_ENUM, Q_SIGNAL, Q_SLOT, Q_INVOKABLE, et c.), Но не разрешает передачу данных между потоками, в этом случае он должен быть зарегистрирован с использованием qRegisterMetaType<MyClass::ErrorCode>("ErrorCode"):

main. cpp

#include <QGuiApplication>
#include <QQuickView>
#include "MyClass.h"

static void registerTypes(){
    <b>qRegisterMetaType<MyClass::ErrorCode>("ErrorCode");</b>
    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();
}
0 голосов
/ 21 января 2020

ваш тип "ErrorCode" определен только в потоке (не в основном)

  1. Для пользовательских типов вы можете использовать (прочитайте это https://doc.qt.io/qt-5/qmetatype.html)

    Q_DECLARE_METATYPE (ErrorCode);

  2. Использовать стандартные типы для аргументов (int, QMap, QString ....)

...