一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如:

QObject::connect: Cannot queue arguments of type 'ThreadSignal'

(Make sure 'ThreadSignal' is registered using qRegisterMetaType().)

或者

QObject::connect: Cannot queue arguments of type 'BYTE[5]'

(Make sure 'BYTE[5]' is registered using qRegisterMetaType().)

或者

QObject::connect: Cannot queue arguments of type 'QMap<QString,CommDevice*>'

(Make sure 'QMap<QString,CommDevice*>' is registered using qRegisterMetaType().)

出现如此问题,在于QT对数据类型未知,按照此提示在连接信号与槽之前,调用 qRegisterMetaType()解决。直接上代码,如下:

qRegisterMetaType<ThreadSignal>("ThreadSignal");

或者

qRegisterMetaType<BYTE * >("BYTE[5]"); //请注意这一行,关于如何注册数组类型

或者

 这种情况有点复杂,由于QMap<QString,CommDevice*> 在qRegisterMetaType<QMap<QString,CommDevice*>>("QMap<QString,CommDevice*>")会报错,无法识别,故可才采用别名的方式:

typedef QMap<QString,CommDevice*> MP_COMMDEVICES;

然后注册采用

qRegisterMetaType<MP_COMMDEVICES>("MP_COMMDEVICES");即可注册成功。

关键点:此处的注册语句qRegisterMetaType()一定要在connect之前执行。如果是信号槽在不同线程的情况下,则需要采用以下方式先利用信号槽调用qRegisterMetaType()注册,然后再利用信号槽建立connect,而不是在构造函数中简单的将qRegisterMetaType语句放在connect语句之前执行这么简单,因为构造函数是在生成该对象的线程中执行的。具体参考以下代码:

 TcpConnectManage.h

 #ifndef TCPCONNECTMANAGE_H
#define TCPCONNECTMANAGE_H #include <QObject>
#include <QThread>
#include "Protocol.h" typedef QMap<QString,CommDevice*> MP_COMMDEVICES;//QMap<QString,CommDevice*>无法在qRegisterMetaType中识别,故采用别名方式 class TcpConnectManage : public QObject
{
Q_OBJECT
public:
explicit TcpConnectManage(QObject *parent = );
......
void connectKeep(QMap<QString, Protocol *> *protocols, MP_COMMDEVICES comm_devices);
......
///
/// \brief registerReflex 注册反射类
///
void registerReflex();
///
/// \brief createConnect 本函数配合对应的信号槽的目的主要是,为了注册
///
void createConnect(); signals:
void sigConnectKeep(QMap<QString, Protocol *> *protocols, MP_COMMDEVICES comm_devices);
void sigRegisterReflex();
void sigCreateConnect();
public slots:
void sltConnectKeep(QMap<QString, Protocol *> *protocols, MP_COMMDEVICES comm_devices);
void sltRegisterReflex();
void sltCreateConnect();
}; #endif // TCPCONNECTMANAGE_H
 #include "TcpConnectManage.h"

 TcpConnectManage::TcpConnectManage(QObject *parent) :
QObject(parent)
{
connect(this,SIGNAL(sigRegisterReflex()),this,SLOT(sltRegisterReflex()));
connect(this,SIGNAL(sigCreateConnect()),this,SLOT(sltCreateConnect()));
} ...... void TcpConnectManage::registerReflex()
{
emit sigRegisterReflex();
} void TcpConnectManage::createConnect()
{
emit sigCreateConnect();
} ...... void TcpConnectManage::sltRegisterReflex()
{
//信号槽中使用的自定义类型注册
qRegisterMetaType<MP_COMMDEVICES>("MP_COMMDEVICES"); //类注册
......
} void TcpConnectManage::sltCreateConnect()
{
connect(this,SIGNAL(sigConnectKeep(QMap<QString,Protocol*>*,MP_COMMDEVICES)),
this,SLOT(sltConnectKeep(QMap<QString,Protocol*>*,MP_COMMDEVICES)));
}

注意:此处

typedef QMap<QString,CommDevice*> MP_COMMDEVICES;//QMap<QString,CommDevice*>无法在qRegisterMetaType中识别,故采用别名方式
不能为
typedef QMap<QString,CommDevice*>& MP_COMMDEVICES;//QMap<QString,CommDevice*>无法在qRegisterMetaType中识别,故采用别名方式
即参数为引用类型,会报以下错误

原因:template argument deduction/substitution failed 模板函数的参数类型不能通过表达式推导

关于模板参数的推导,参考:【C++】模板参数推导(template argument deduction)http://www.cnblogs.com/visayafan/archive/2011/11/27/2265400.html

其实在信号槽连接方式使用Qt:QueuedConnection时,其中的参数完全没有必要使用引用类型,因为此种方式下,信号参数为引用类型,则还是会另外复制一份的。

       其实不止是自定义类型,包括QList、QMap这种QT的容器类也是一样需要注册。估计QT只是给少数几个类如QString注册了。还有少数原生类型,比如发现__int64也是需要注册的,qRegisterMetaType<__int64>("__int64");。
       另外有个建议:就是使用信号和槽的时候,尽量使用QT而不是标准库的容器类,比如QString、QList等等。这主要是出于性能上的考虑。QT的容器包括QString都使用了implicitly shared技术,所以拷贝构造函数运行速度是很快的。很适用于信号槽这种封包机制。因为封包本质上就是把函数的地址和函数的所有入参都保存起来,所以免不了调用函数入参的拷贝构造函数。
 
  注意:
关于网上搜说的另一种解决办法:connect时添加参数Qt::DirectConnection,以保证其不被放入信号队列,不告警从而达到想要的效果,但这种办法不一定能解决该问题,因为如果是信号槽在不同线程执行,目的就是要让槽在另一个线程队列执行,如果采用Qt::DirectConnection,则槽函数将在发出信号的线程中执行,这与采用多线程的目的不符,故不建议这样使用。具体学习“Qt信号槽的几种连接方式和执行方式”
http://www.dushibaiyu.com/2015/07/qt-signals-slots-connect.html

 
参考资料:
1、http://blog.csdn.net/runyon1982/article/details/49018855
2、http://www.tuicool.com/articles/yEZBv2
3、http://www.dushibaiyu.com/2015/07/qt-signals-slots-connect.html
4、http://www.cnblogs.com/visayafan/archive/2011/11/27/2265400.html

 

QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类的更多相关文章

  1. QT信号槽connect的第五个参数

    用过QT的小伙伴都知道连接信号槽的connect方法,但是这个方法有第五个参数,一般都是用的默认的 connect(th,SIGNAL(started()),tmpmyobject,SLOT(show ...

  2. QT信号槽的六个优点(虽然直接调用函数也可解决问题,但要在具体的函数中传递指针,多对一和解除关系也够麻烦的)

    信号槽是Qt中特有的概念.它使得程序员将不同的object绑定起来,而object对象间并不需要对相互了解. Slots也是普通的c++方法,它们可以是virtual;可以被重载;可以使private ...

  3. 如何在Qt中使用自定义数据类型

    这里我们使用下面这个struct来做说明(这里不管是struct还是class都一样): struct Player { int number; QString firstName; QString ...

  4. QT为QLabel添加Click事件(如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件)

    其实就是改写了一个函数:mouseReleaseEvent,当在QLabel放开鼠标的时,就发射点击信号. #ifndef CLICKEDLABEL_H_ #define CLICKEDLABEL_H ...

  5. QT信号槽详解

    1         QT信号槽详解 1.1  信号和槽的定义 信号是触发信号,例如按钮的点击触发一个clicked信号,槽是用来接收信号,并处理信号,相当于信号响应函数.一个信号可以关联多个槽函数,信 ...

  6. Qt信号槽-原理分析

    目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...

  7. QT源码之Qt信号槽机制与事件机制的联系

    QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...

  8. Qt信号槽源码剖析(一)

    大家好,我是IT文艺男,来自一线大厂的一线程序员 大家在使用Qt开发程序时,都知道怎么使用Qt的信号槽,但是Qt信号槽是怎么工作的? 大部分人仍然不知道:也就是说大家只知道怎么使用,却不知道基于什么原 ...

  9. Qt信号槽的一些事(第一次知道信号还有返回值,以及Qt::UniqueConnection)

    注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...

随机推荐

  1. [UOJ282]长度测量鸡

    思路: 数学归纳. 设最少所需刻度数为$s$,则$n和s$的关系为: $n=1,s=0;$ $n=2,s=1;$ $n=3,s=3;$ ... 观察发现$s=n(n-1)/2$,得到$sn$时,满足条 ...

  2. HDU5293 : Tree chain problem

    问题即:选择价值和最多的链,使得每个点最多被一条链覆盖. 那么考虑其对偶问题:选择最少的点(每个点可以重复选),使得每条链上选了至少$w_i$个点. 那么将链按照LCA的深度从大到小排序,每次若发现点 ...

  3. 深入理解JVM(3)——垃圾收集策略详解

    Java虚拟机的内存模型分为五部分:程序计数器.Java虚拟机栈.本地方法栈.堆.方法区. 程序计数器.Java虚拟机栈.本地方法栈都是线程私有的,也就是每个线程都拥有这三个区域,而且这三个区域会随着 ...

  4. Spring+Quartz实现定时任务的配置方法(转)

    1.Scheduler的配置 <bean id="myScheduler" class="org.springframework.scheduling.quartz ...

  5. 【迎圣诞,拿大奖】+流量分析+Writeup分享

    太菜了太菜了,刚见到jsfuck时竟然不知道什么东西,自己都不敢说自己做过实验吧上的那道jsfuck题了. 进入正题: 首先解压发现两个文件,一个流量分析包,哇哇哇,我正好刚学了几天wireshark ...

  6. RFC-RTSP

    Network Working Group H. Schulzrinne Request for Comments: 2326 Columbia U. Category: Standards Trac ...

  7. python动态构建类(类似声明)

    对于类实例的动态构建,那是非常的简单.可要在代码中动态的构建类,然后该类还能够被使用,那得多么的强大呀. 在Python中,内建的__builtin__提供了一个type的方法,用该方法可以动态的构建 ...

  8. 倾斜摄影数据OSGB进入到ArcGIS平台相关问题小结

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zglybl/article/details/75252288      随着倾斜摄影技术的发展,大家 ...

  9. RestTemplate发送请求并携带header信息 RestTemplate post json格式带header信息

    原文地址:  http://www.cnblogs.com/hujunzheng/p/6018505.html RestTemplate发送请求并携带header信息   v1.使用restTempl ...

  10. Maven中classifier

    1.classifier概述 classifier通常用于区分从同一POM构建的具有不同内容的构件(artifact).它是可选的,它可以是任意的字符串,附加在版本号之后. 2.使用场景 场景一:区分 ...