Qt中注册定义类型qRegisterMetaType和Q_DECLARE_METATYPE的总结

概述

如果想要我们自己自定义的类型也可以有 Qt 自己类型的功能的话,就必须注册我们的类型到 Qt 中,这样才可以在信号和槽的通讯机制中使用我们的自定义的类型。

Q_DECLARE_METATYPE

被 Q_DECLARE_METATYPEQ 标记的类型可以让Q MetaType 查询到类型,也可以让QVariant识别到。

struct MyStruct {
    QString name;
};
Q_DECLARE_METATYPE(MyStruct)

若对象包含在自定义的命名空间中时,注册时要带上完整的命令空间

Q_DECLARE_METATYPE(NSP::MyStruct)

qRegisterMetaType

使用 qRegisterMetaType 注册自定义类型到元对象系统中主要作用为 QObject 的属性系统(信号槽)中使用该自定义类型。

一般在第一次定义信号槽连接 connect 前进行注册,参数建议为同名字符串参数:

qRegisterMetaType<MyStruct>("MyStruct");

若已经使用 Q_DECLARE_METATYPEQ 标记过该类型,可以使用其不带参数的版本:

qRegisterMetaType<MyStruct>();

同样的,若对象包含在自定义的命名空间中时,注册时要带上完整的命令空间,如:

qRegisterMetaType<NSP::MyStruct>("NSP::MyStruct");

若要用信号槽传递其引用值,也需要注册:

qRegisterMetaType<MyStruct>("MyStruct&");

若要用信号槽传递其智能指针,也需要注册:

qRegisterMetaType<QSharedPointer<MyStruct>>("QSharedPointer<MyStruct>");

总结

 在Qt中,想要使用signal/slot来传递自定义的类型时,需要使用qRegisterMetaType来注册。其原因是:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象。用qRegisterMetaType对自定义的类型进行注册,就是为了告诉Qt如何去做这些事情。

      步骤:(以自定义MyDataType类型为例)

     1、自定MyDataType 类型,在这个类型的顶部包含:#include <QMetaType>

     2、在类型定义完成后,加入声明:Q_DECLARE_METATYPE(MyDataType);

     3、在main()函数中注册这种类型:qRegisterMetaType<MyDataType>("MyDataType");

     4、如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType<MyDataType>("MyDataType&");

例:   
 

#include <QMetaType>       
class MyDataType
  {     
   public:     
   MyDataType();     
   MyDataType(int, double);        
private:      
};     
Q_DECLARE_METATYPE(MyDataType);     
  
 
int main(int argc, char *argv[])     
{     
QApplication app(argc, argv); 
   qRegisterMetaType<MyDataType>("MyDataType");     
   qRegisterMetaType<MyDataType>("MyDataType&");     
}

不跨线程的话,使用自定义的类型使用signal/slot来传递,没有什么问题。

但如果是跨线程的使用,则没有这么简单。


直接使用的话,会产生下面这种错误:(假定自定义类为MyClass)
QObject::connect: Cannot queue arguments of type 'MyDataType' (Make sure 'MyDataType' is registed using qRegisterMetaType().)
实际运行中也会发现,该信号槽没有起作用。


其实解决方法在错误提示中已经给出了:Make sure 'MyDataType' is registed using qRegisterMetaType().
即使用qRegisterMetaType()将自定义类型进行注册


这里总结使用方法如下:
1、注册位置:在第一次使用此类链接跨线程的signal/slot之前,一般在当前类的构造函数中进行注册;
2、注册方法:在当前类的顶部包含:#include <QMetaType>,构造函数中加入代码:qRegisterMetaType<MyDataType>("MyDataType");
3、Myclass的引用类型需单独注册:qRegisterMetaType<MyDataType>("MyDataType&");


如果不实用这种方法,还有一种办法来使跨线程的signal/slot起作用,即使用connect函数的Qt::DirectConnection参数

connect(A,SIGNAL(sendA(MyDataType)),B,SLOT(getA(MyDataType)),Qt::DirectConnection);

但此方法官方不推荐使用,认为其不安全。不过在笔者实际使用过程中,未发现有不妥之处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值