QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题

您所在的位置:网站首页 qt怎么定义数组 QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题

QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题

2024-05-21 16:07| 来源: 网络整理| 查看: 265

   一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或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' 

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

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

   qRegisterMetaType("ThreadSignal");

或者

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

或者

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

typedef QMap MP_COMMDEVICES;

然后注册采用

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

 

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

1 TcpConnectManage.h 2 3 #ifndef TCPCONNECTMANAGE_H 4 #define TCPCONNECTMANAGE_H 5 6 #include 7 #include 8 #include "Protocol.h" 9 10 11 typedef QMap MP_COMMDEVICES;//QMap无法在qRegisterMetaType中识别,故采用别名方式 12 13 class TcpConnectManage : public QObject 14 { 15 Q_OBJECT 16 public: 17 explicit TcpConnectManage(QObject *parent = 0); 18 ...... 19 void connectKeep(QMap *protocols, MP_COMMDEVICES comm_devices); 20 ...... 21 /// 22 /// \brief registerReflex 注册反射类 23 /// 24 void registerReflex(); 25 /// 26 /// \brief createConnect 本函数配合对应的信号槽的目的主要是,为了注册 27 /// 28 void createConnect(); 29 30 signals: 31 void sigConnectKeep(QMap *protocols, MP_COMMDEVICES comm_devices); 32 void sigRegisterReflex(); 33 void sigCreateConnect(); 34 public slots: 35 void sltConnectKeep(QMap *protocols, MP_COMMDEVICES comm_devices); 36 void sltRegisterReflex(); 37 void sltCreateConnect(); 38 }; 39 40 #endif // TCPCONNECTMANAGE_H 1 #include "TcpConnectManage.h" 2 7 8 TcpConnectManage::TcpConnectManage(QObject *parent) : 9 QObject(parent) 10 { 11 connect(this,SIGNAL(sigRegisterReflex()),this,SLOT(sltRegisterReflex())); 12 connect(this,SIGNAL(sigCreateConnect()),this,SLOT(sltCreateConnect())); 13 } 14 15 ...... 16 17 void TcpConnectManage::registerReflex() 18 { 19 emit sigRegisterReflex(); 20 } 21 22 void TcpConnectManage::createConnect() 23 { 24 emit sigCreateConnect(); 25 } 26 27 ...... 28 29 void TcpConnectManage::sltRegisterReflex() 30 { 31 //信号槽中使用的自定义类型注册 32 qRegisterMetaType("MP_COMMDEVICES"); 33 34 //类注册 35 ...... 36 } 37 38 void TcpConnectManage::sltCreateConnect() 39 { 40 connect(this,SIGNAL(sigConnectKeep(QMap*,MP_COMMDEVICES)), 41 this,SLOT(sltConnectKeep(QMap*,MP_COMMDEVICES))); 42 }

注意:此处 

typedef QMap MP_COMMDEVICES;//QMap无法在qRegisterMetaType中识别,故采用别名方式不能为 typedef QMap& MP_COMMDEVICES;//QMap无法在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");。        另外有个建议:就是使用信号和槽的时候,尽量使用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

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3