Qt自定义类型信号槽发送接收,以及跨线程发送问题(详细篇)

Qt自定义数据类型信号槽传递

1.Qt信号槽是Qt引以为傲的消息传递方式,这里我们不重点讨论信号槽,聊聊自定义数据发送问题,首先我们来看看Qt内置的一些数据类型:

 enum Type {
        Invalid = QMetaType::UnknownType,
        Bool = QMetaType::Bool,
        Int = QMetaType::Int,
        UInt = QMetaType::UInt,
        LongLong = QMetaType::LongLong,
        ULongLong = QMetaType::ULongLong,
        Double = QMetaType::Double,
        Char = QMetaType::QChar,
        Map = QMetaType::QVariantMap,
        List = QMetaType::QVariantList,
        String = QMetaType::QString,
        StringList = QMetaType::QStringList,
        ByteArray = QMetaType::QByteArray,
        BitArray = QMetaType::QBitArray,
        Date = QMetaType::QDate,
        Time = QMetaType::QTime,
        DateTime = QMetaType::QDateTime,
        Url = QMetaType::QUrl,
        Locale = QMetaType::QLocale,
        Rect = QMetaType::QRect,
        RectF = QMetaType::QRectF,
        Size = QMetaType::QSize,
        SizeF = QMetaType::QSizeF,
        Line = QMetaType::QLine,
        LineF = QMetaType::QLineF,
        Point = QMetaType::QPoint,
        PointF = QMetaType::QPointF,
        RegExp = QMetaType::QRegExp,
        RegularExpression = QMetaType::QRegularExpression,
        Hash = QMetaType::QVariantHash,
        EasingCurve = QMetaType::QEasingCurve,
        Uuid = QMetaType::QUuid,
        ModelIndex = QMetaType::QModelIndex,
        PersistentModelIndex = QMetaType::QPersistentModelIndex,
        LastCoreType = QMetaType::LastCoreType,

        Font = QMetaType::QFont,
        Pixmap = QMetaType::QPixmap,
        Brush = QMetaType::QBrush,
        Color = QMetaType::QColor,
        Palette = QMetaType::QPalette,
        Image = QMetaType::QImage,
        Polygon = QMetaType::QPolygon,
        Region = QMetaType::QRegion,
        Bitmap = QMetaType::QBitmap,
        Cursor = QMetaType::QCursor,
        KeySequence = QMetaType::QKeySequence,
        Pen = QMetaType::QPen,
        TextLength = QMetaType::QTextLength,
        TextFormat = QMetaType::QTextFormat,
        Matrix = QMetaType::QMatrix,
        Transform = QMetaType::QTransform,
        Matrix4x4 = QMetaType::QMatrix4x4,
        Vector2D = QMetaType::QVector2D,
        Vector3D = QMetaType::QVector3D,
        Vector4D = QMetaType::QVector4D,
        Quaternion = QMetaType::QQuaternion,
        PolygonF = QMetaType::QPolygonF,
        Icon = QMetaType::QIcon,
        LastGuiType = QMetaType::LastGuiType,

        SizePolicy = QMetaType::QSizePolicy,

        UserType = QMetaType::User,
        LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type
    };

可以看到Qt内置类型很丰富,但是有时候并不能满足千奇百怪的需求。碰到一些自定义数据的时候咋办?别急这里还是有几个办法可以解决的。
这里需要非常注意的一点是如果是在同一个线程使用,那么自定义数据类型可以直接发送并在槽里面接受并不会产生什么错误。只有跨线程使用的时候需要考虑自定义数据发送问题,直接使用会产生错误 QObject::connect: Cannot queue arguments of type’‘xxxx’
(1)方法1:引入头文件#include < QMetaType>,使用 qRegisterMetaType<>()
进行元类型注册;

#ifndef VARTEST_H
#define VARTEST_H

#include <QWidget>
#include <QVariant>
#include <QMetaType>

typedef struct _deviceinfo
{
    QString Mac;           //mac
    int  type;             //类型
}DeviceInfo;

namespace Ui {
class VARTest;
}

class VARTest : public QWidget
{
    Q_OBJECT
public:
    explicit VARTest(QWidget *parent = 0);
    ~VARTest();
signals:
    void sigMsg_A(DeviceInfo info);
public slots:
    void sendMsgSlot();
    void sigASlot(DeviceInfo info);
private:
    Ui::VARTest *ui;
};
#endif // VARTEST_H

VARTest::VARTest(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::VARTest)
{
    ui->setupUi(this);

    qRegisterMetaType<DeviceInfo>("DeviceInfo");

    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(sendMsgSlot()));
    connect(this,SIGNAL(sigMsg_A(DeviceInfo)),this,SLOT(sigASlot(DeviceInfo)));
}

VARTest::~VARTest()
{
    delete ui;
}

void VARTest::sendMsgSlot()
{
    DeviceInfo m_info;
    m_info.Mac = "4E:3F:3D:48";
    m_info.type = 1;
    emit sigMsg_A(m_info);
}

void VARTest::sigASlot(DeviceInfo info)
{
    qDebug()<<"sigA.Mac:"<<info.Mac;
}

这里我们直接在一个GUI线程里做示例没使用多线程,大家可以在多线程验证一遍
在这里插入图片描述
(2)方法2:使用connect函数的第5个参数Qt::DirectConnection
如:connect(objA,SIGNAL(sig(customType)),objB,SLOT(sigSLOT(customType)),Qt::DirectConnection);
这种方法需要慎用,因为数据在信号所在线程发送以后数据直接在槽所在线程执行,可能会导致跨线程问题。
(3)方法3: 以上方法都有一定的局限性,使用qRegisterMetaType注册元类型,一个信号只能发送一个或几个数据类型,如果需要一个信号发送很多数据类型,这个时候就需要一种通用的数据处理方式。这个时候可以利用QVariant。使用这种方式首先要在数据声明下面使用宏声明Q_DECLARE_METATYPE(DeviceInfo)

#ifndef VARTEST_H
#define VARTEST_H

#include <QWidget>
#include <QVariant>
#include <QMetaType>

typedef struct _deviceinfo
{
    QString Mac;           //mac
    int  type;             //类型
}DeviceInfo;
Q_DECLARE_METATYPE(DeviceInfo)

namespace Ui {
class VARTest;
}

class VARTest : public QWidget
{
    Q_OBJECT
public:
    explicit VARTest(QWidget *parent = 0);
    ~VARTest();
signals:
    void sigMsg_B(int id,QVariant values);
public slots:
    void sendMsgSlot();
    void sigBSlot(int id,QVariant values);
private:
    Ui::VARTest *ui;
};

#endif // VARTEST_H

VARTest::VARTest(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::VARTest)
{
    ui->setupUi(this);

    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(sendMsgSlot()));
    connect(this,SIGNAL(sigMsg_B(int,QVariant)),this,SLOT(sigBSlot(int,QVariant)));
}

VARTest::~VARTest()
{
    delete ui;
}

void VARTest::sendMsgSlot()
{
    DeviceInfo m_info;
    m_info.Mac = "4E:3F:3D:48";
    m_info.type = 1;
    QVariant values1;
    values1.setValue(m_info);
    emit sigMsg_B(1,values1);

    int m_value = 999;
    QVariant values2;
    values2.setValue(m_value);
    emit sigMsg_B(2,values2);

    QString str("真有意思!");
    QVariant values3;
    values3.setValue(str);
    emit sigMsg_B(3,values3);

}

void VARTest::sigBSlot(int id,QVariant values)
{
    switch (id) {
    case 1:
    {
        DeviceInfo m_info = values.value<DeviceInfo>();
        qDebug()<<"sigB Mac:"<<m_info.Mac;
        break;
    }
    case 2:
    {
        qDebug()<<"sigB int:"<<values.toInt();
        break;
    }
    case 3:
    {
        qDebug()<<"sigB QString:"<<values.toString();
        break;
    }
    default:
        break;
    }
}

在这里插入图片描述
这种方法非常适合自定义的数据非常多的情况,可以用一个信号发送进行集中处理,能发送自定义数据同时兼顾内置数据类型。

作者:费码程序猿
欢迎技术交流:QQ:255895056
转载请注明出处,如有不当欢迎指正

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中,线程的信号连接需要使用Qt线程间通信机制。下面是一些基本的步骤: 1. 使用QObject::moveToThread()方法将对象移动到目标线程。 2. 在目标线程中创建一个QObject,并调用QObject::connect()方法将信号连接起来。 3. 如果信号需要传递参数,则需要使用Qt的元对象系统(Meta-Object System)来注册参数类型。可以使用Q_DECLARE_METATYPE宏来注册自定义类型。 4. 在发送信号时,需要使用QMetaObject::invokeMethod()方法,将该方法的第一个参数设置为接收信号的对象,第二个参数设置为接收信号的函数名,第三个参数设置为Qt::QueuedConnection,以确保信号被放入目标线程的事件队列中。 下面是一个简单的示例: ```cpp class Worker : public QObject { Q_OBJECT signals: void resultReady(int result); public slots: void doWork() { int result = 0; // 计算结果 emit resultReady(result); } }; class Controller : public QObject { Q_OBJECT public: Controller() { Worker *worker = new Worker(); QThread *workerThread = new QThread(); worker->moveToThread(workerThread); connect(workerThread, &QThread::started, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResult); workerThread->start(); } ~Controller() { // 停止线程 } public slots: void handleResult(int result) { // 处理结果 } }; ``` 在这个例子中,Worker对象的doWork()方法在一个新的线程中执行,当计算完成后,使用信号resultReady(int result)发送结果。Controller对象将自己的handleResult(int result)连接到该信号上,在目标线程中处理结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值