如果要在Qt信号槽中使用自定义类型,需要注意使用qRegisterMetaType对自定义类型进行注册。
当然在不跨线程时使用自定义类型signal/slot来传递,可能不会出现什么问题;一旦涉及跨线程就很容易出错,回想下信号槽的作用就是用来对象与对象之间通信的,难免会跨线程,建议在使用自定义类型利用信号槽通信时,最好先通过qRegisterMetaType()将自定义类型进行注册,以免出错。
总结qRegisterMetaType使用方法如下:
1、注册位置:
在第一次使用此类链接跨线程的signal/slot之前,一般在当前类的构造函数中进行注册。
2、注册方法:
在当前类的顶部包含:#include <QMetaType>;
构造函数中加入代码:qRegisterMetaType<MyClass>("Myclass");
3、Myclass的引用类型需单独注册:
qRegisterMetaType<MyClass>("Myclass&");
实例测试:
如果是自己定义的类型TextAndNumber,如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:
QObject::connect: Cannot queue arguments of type 'TextAndNumber' (Make sure 'TextAndNumber'
.is registed using qRegisterMetaType().)
原因:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象,而为了让Qt知道怎样去作这些事情,参数的类型需要使用qRegisterMetaType来注册(如错误提示中的说明)。
步骤:(以自定义TextAndNumber类型为例)
自定一种类型,在这个类型的顶部包含:#include
在类型定义完成后,加入声明:Q_DECLARE_METATYPE(TextAndNumber); # 此步骤可忽略
在main()函数中注册这种类型:qRegisterMetaType("TextAndNumber");
如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType("TextAndNumber&");
#include <QMetaType>
// # ...
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<TextAndNumber>(TextAndNumber);
qRegisterMetaType<TextAndNumber>(TextAndNumber&);
TextDevice device;
TextThread foo(foo), bar(bar);
QObject::connect(&foo, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
QObject::connect(&bar, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
}
传送门:qt多线程系列文章目录
参考文章:
1、qRegisterMetaType用法总结
https://blog.csdn.net/u013360881/article/details/78878471