QT QObject::connect函数的学习

2024-06-01 01:38
文章标签 函数 学习 qt connect qobject

本文主要是介绍QT QObject::connect函数的学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自http://blog.csdn.net/ybjx111/article/details/8272405

从Qobject(QObject.h)源码中可以看到QObject::connect的定义是这样的:

[cpp]  view plain copy
  1. static bool connect(const QObject *sender, const char *signal,  
  2.                     const QObject *receiver, const char *member, Qt::ConnectionType =  
  3.     #ifdef qdoc  
  4.                         Qt::AutoConnection  
  5.     #else  
  6.         #ifdef QT3_SUPPORT  
  7.                             Qt::AutoCompatConnection  
  8.     #else  
  9.                                 Qt::AutoConnection  
  10.         #endif  
  11.     #endif  
  12.     );  
  13. inline bool connect(const QObject *sender, const char *signal,  
  14.                     const char *member, Qt::ConnectionType type =  
  15.     #ifdef qdoc  
  16.                      Qt::AutoConnection  
  17.     #else  
  18.         #ifdef QT3_SUPPORT  
  19.                                 Qt::AutoCompatConnection  
  20.         #else  
  21.                                 Qt::AutoConnection  
  22.         #endif  
  23.     #endif  
  24.     ) const;  

其中第二个connect的实现其实只有一句话:

[cpp]  view plain copy
  1. return connect(asender, asignal, this, amember, atype); }  

所以对于connect函数的学习其实就是研究第一个connect函数。

我们在使用connect函数的时候一般是这样调用的:

[cpp]  view plain copy
  1. connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));  

这里用到了两个宏:SIGNAL() 和SLOT();通过connect声明可以知道这两个宏最后倒是得到一个const char*类型。
在qobjectdefs.h中可以看到SIGNAL() 和SLOT()的宏定义:

[cpp]  view plain copy
  1. #ifndef QT_NO_DEBUG  
  2. # define QLOCATION "\0"__FILE__":"QTOSTRING(__LINE__)  
  3. # define METHOD(a)   qFlagLocation("0"#a QLOCATION)  
  4. # define SLOT(a)     qFlagLocation("1"#a QLOCATION)  
  5. # define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)  
  6. #else  
  7. # define METHOD(a)   "0"#a  
  8. # define SLOT(a)     "1"#a  
  9. # define SIGNAL(a)   "2"#a  
  10. #endif  

所以这两个宏的作用就是把函数名转换为字符串并且在前面加上标识符。

比如:SIGNAL(read())展开后就是"2read()";同理SLOT(read())展开后就是"1read()"。

[cpp]  view plain copy
  1. connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));  
  2. 实际上就是connect(sender,“2signal()”,receiver,“1slot())”;  

搞明白了实际的参数就可以来看connect的真正实现过程了,在QObject.cpp文件中可以找到connect的实现代码。

[cpp]  view plain copy
  1. bool QObject::connect(const QObject *sender, const char *signal,  
  2.                       const QObject *receiver, const char *method,  
  3.                       Qt::ConnectionType type)  
  4. {  
  5.     {  
  6.         const void *cbdata[] = { sender, signal, receiver, method, &type };  
  7.         if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))  
  8.             return true;  
  9.     }  
  10.   
  11.     if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {  
  12.         qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",  
  13.                  sender ? sender->metaObject()->className() : "(null)",  
  14.                  (signal && *signal) ? signal+1 : "(null)",  
  15.                  receiver ? receiver->metaObject()->className() : "(null)",  
  16.                  (method && *method) ? method+1 : "(null)");  
  17.         return false;  
  18.     }  
  19.     QByteArray tmp_signal_name;  
  20.   
  21.     if (!check_signal_macro(sender, signal, "connect""bind"))  
  22.         return false;  
  23.     const QMetaObject *smeta = sender->metaObject();  
  24.     const char *signal_arg = signal;  
  25.     ++signal; //skip code  
  26.     int signal_index = smeta->indexOfSignal(signal);  
  27.     if (signal_index < 0) {  
  28.         // check for normalized signatures  
  29.         tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);  
  30.         signal = tmp_signal_name.constData() + 1;  
  31.   
  32.         signal_index = smeta->indexOfSignal(signal);  
  33.         if (signal_index < 0) {  
  34.             err_method_notfound(sender, signal_arg, "connect");  
  35.             err_info_about_objects("connect", sender, receiver);  
  36.             return false;  
  37.         }  
  38.     }  
  39.   
  40.     QByteArray tmp_method_name;  
  41.     int membcode = extract_code(method);  
  42.   
  43.     if (!check_method_code(membcode, receiver, method, "connect"))  
  44.         return false;  
  45.     const char *method_arg = method;  
  46.     ++method; // skip code  
  47.   
  48.     const QMetaObject *rmeta = receiver->metaObject();  
  49.     int method_index = -1;  
  50.     switch (membcode) {  
  51.     case QSLOT_CODE:  
  52.         method_index = rmeta->indexOfSlot(method);  
  53.         break;  
  54.     case QSIGNAL_CODE:  
  55.         method_index = rmeta->indexOfSignal(method);  
  56.         break;  
  57.     }  
  58.     if (method_index < 0) {  
  59.         // check for normalized methods  
  60.         tmp_method_name = QMetaObject::normalizedSignature(method);  
  61.         method = tmp_method_name.constData();  
  62.         switch (membcode) {  
  63.         case QSLOT_CODE:  
  64.             method_index = rmeta->indexOfSlot(method);  
  65.             break;  
  66.         case QSIGNAL_CODE:  
  67.             method_index = rmeta->indexOfSignal(method);  
  68.             break;  
  69.         }  
  70.     }  
  71.   
  72.     if (method_index < 0) {  
  73.         err_method_notfound(receiver, method_arg, "connect");  
  74.         err_info_about_objects("connect", sender, receiver);  
  75.         return false;  
  76.     }  
  77.     if (!QMetaObject::checkConnectArgs(signal, method)) {  
  78.         qWarning("QObject::connect: Incompatible sender/receiver arguments"  
  79.                  "\n        %s::%s --> %s::%s",  
  80.                  sender->metaObject()->className(), signal,  
  81.                  receiver->metaObject()->className(), method);  
  82.         return false;  
  83.     }  
  84.   
  85.     int *types = 0;  
  86.     if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)  
  87.             && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))  
  88.         return false;  
  89.   
  90.     QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);  
  91.     const_cast<QObject*>(sender)->connectNotify(signal - 1);  
  92.     return true;  
  93. }  


上面是去除了debug代码的connect实现。

 

[cpp]  view plain copy
  1. const void *cbdata[] = { sender, signal, receiver, method, &type };  
  2. if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))  
  3.       return true;  

判断连接是否已经建立。
QInternal::ConnectCallback在qglobal.cpp中实现。

[cpp]  view plain copy
  1. bool QInternal::activateCallbacks(Callback cb, void **parameters)  
  2. {  
  3.     Q_ASSERT_X(cb >= 0, "QInternal::activateCallback()""Callback id must be a valid id");  
  4.   
  5.     QInternal_CallBackTable *cbt = global_callback_table();  
  6.     if (cbt && cb < cbt->callbacks.size()) {  
  7.         QList<qInternalCallback> callbacks = cbt->callbacks[cb];  
  8.         bool ret = false;  
  9.         for (int i=0; i<callbacks.size(); ++i)  
  10.             ret |= (callbacks.at(i))(parameters);  
  11.         return ret;  
  12.     }  
  13.     return false;  
  14. }  

QInternal_CallBackTable 定义为(qglobal.cpp)

[cpp]  view plain copy
  1. struct QInternal_CallBackTable {  
  2.     QVector<QList<qInternalCallback> > callbacks;  
  3. };  

qInternalCallback定义为(qnamespace.h)

[cpp]  view plain copy
  1. typedef bool (*qInternalCallback)(void **);这是一个函数指针 返回值是bool,只有一个参数为void**。这个指针在调用registerCallback加入列表。  


 

 

[cpp]  view plain copy
  1. if (!check_signal_macro(sender, signal, "connect""bind"))  
  2.     return false;  

判断signal是否合法。

在QObject.cpp文件中可以找到check_signal_macro的实现

[cpp]  view plain copy
  1. static bool check_signal_macro(const QObject *sender, const char *signal,  
  2.                                 const char *func, const char *op)  
  3. {  
  4.     int sigcode = extract_code(signal);  
  5.     if (sigcode != QSIGNAL_CODE) {  
  6.         if (sigcode == QSLOT_CODE)  
  7.             qWarning("Object::%s: Attempt to %s non-signal %s::%s",  
  8.                      func, op, sender->metaObject()->className(), signal+1);  
  9.         else  
  10.             qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s",  
  11.                      func, op, sender->metaObject()->className(), signal);  
  12.         return false;  
  13.     }  
  14.     return true;  
  15. }  


extract的实现也在QObject中,它就是去字符串第一个字符,并且只取低2位的值。

[cpp]  view plain copy
  1. static int extract_code(const char *member)  
  2. {  
  3.     // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE  
  4.     return (((int)(*member) - '0') & 0x3);  
  5. }  


这里又有两个宏:QSIGNAL_CODE 和QSLOT_CODE。它们也是在qobjectdefs.h文件中定义的。

[cpp]  view plain copy
  1. #ifdef QT3_SUPPORT  
  2. #define METHOD_CODE   0                        // member type codes  
  3. #define SLOT_CODE     1  
  4. #define SIGNAL_CODE   2  
  5. #endif  


这个定义与之前的SIGNAL和SLOT的定义是对应的。

 

 



[cpp]  view plain copy
  1. const QMetaObject *smeta = sender->metaObject();  
  2. const char *signal_arg = signal;  
  3. ++signal; //skip code  
  4. int signal_index = smeta->indexOfSignal(signal);  
  5. if (signal_index < 0) {  
  6.     // check for normalized signatures  
  7.     tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);  
  8.     signal = tmp_signal_name.constData() + 1;  
  9.   
  10.     signal_index = smeta->indexOfSignal(signal);  
  11.     if (signal_index < 0) {  
  12.         err_method_notfound(sender, signal_arg, "connect");  
  13.         err_info_about_objects("connect", sender, receiver);  
  14.         return false;  
  15.     }  
  16. }  

获取signal的索引。

metaObject()是在moc_name.cpp文件中生成的。

[cpp]  view plain copy
  1. return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;  

其中staticMetaObject也是在moc文件中定义的

[cpp]  view plain copy
  1. const QMetaObject MainWindow::staticMetaObject = {  
  2.     { &QMainWindow::staticMetaObject, qt_meta_stringdata_MainWindow,  
  3.       qt_meta_data_MainWindow, 0 }  
  4. };  

qt_meta_stringdata_MainWindow(具体名字和类名有关)就是staticconstchar[]类型。它记录了全部的signals和slots等的函数名、返回值和参数表的信息。

qt_meta_data_MainWindow(具体名字和类名有关)是staticconstuint[]类型。它记录了每一个函数的函数名、返回值和参数表在qt_meta_stringdata_MainWindow中的索引。同时它还记录了每一个函数的类型具体在qmetaobject.cpp文件中定义。

[cpp]  view plain copy
  1. enum MethodFlags  {  
  2.     AccessPrivate = 0x00,  
  3.     AccessProtected = 0x01,  
  4.     AccessPublic = 0x02,  
  5.     AccessMask = 0x03, //mask  
  6.   
  7.     MethodMethod = 0x00,  
  8.     MethodSignal = 0x04,  
  9.     MethodSlot = 0x08,  
  10.     MethodConstructor = 0x0c,  
  11.     MethodTypeMask = 0x0c,  
  12.   
  13.     MethodCompatibility = 0x10,  
  14.     MethodCloned = 0x20,  
  15.     MethodScriptable = 0x40  
  16. };  


indexOfSignal(signal);的实现在qmetaobject.cpp中。其主要作用是利用qt_meta_stringdata_MainWindow 和qt_meta_data_MainWindow查找已经定义了的signal并返回索引。
 

 

 

[cpp]  view plain copy
  1. QByteArray tmp_method_name;  
  2. int membcode = extract_code(method);  
  3.   
  4. if (!check_method_code(membcode, receiver, method, "connect"))  
  5.     return false;  
  6. const char *method_arg = method;  
  7. ++method; // skip code  
  8.   
  9. const QMetaObject *rmeta = receiver->metaObject();  
  10. int method_index = -1;  
  11. switch (membcode) {  
  12. case QSLOT_CODE:  
  13.     method_index = rmeta->indexOfSlot(method);  
  14.     break;  
  15. case QSIGNAL_CODE:  
  16.     method_index = rmeta->indexOfSignal(method);  
  17.     break;  
  18. }  
  19. if (method_index < 0) {  
  20.     // check for normalized methods  
  21.     tmp_method_name = QMetaObject::normalizedSignature(method);  
  22.     method = tmp_method_name.constData();  
  23.     switch (membcode) {  
  24.     case QSLOT_CODE:  
  25.         method_index = rmeta->indexOfSlot(method);  
  26.         break;  
  27.     case QSIGNAL_CODE:  
  28.         method_index = rmeta->indexOfSignal(method);  
  29.         break;  
  30.     }  
  31. }  
  32.   
  33. if (method_index < 0) {  
  34.     err_method_notfound(receiver, method_arg, "connect");  
  35.     err_info_about_objects("connect", sender, receiver);  
  36.     return false;  
  37. }  


校验method并且查找它的索引。过程与signal类似。

 

[cpp]  view plain copy
  1. if (!QMetaObject::checkConnectArgs(signal, method)) {  
  2.     qWarning("QObject::connect: Incompatible sender/receiver arguments"  
  3.              "\n        %s::%s --> %s::%s",  
  4.              sender->metaObject()->className(), signal,  
  5.              receiver->metaObject()->className(), method);  
  6.     return false;  
  7. }  


判断signal和method是否兼容,checkConnectArgs函数的在qmetaObject.cpp文件中实现。这个函数校验了signal和method的参数。当两者的参数一致或method参数比signal参数少(method与signal前几个参数一致)的时候返回true,其它返回false。

 

 

 

[cpp]  view plain copy
  1. int *types = 0;  
  2. if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)  
  3.         && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))  
  4.     return false;  


如果是以发消息的方式执行method就需要对参数类型进行判断。queuedConnectionTypes在QObject.cpp实现。实际上是在QMetatype.cpp中定义了一个

static conststruct { constchar * typeName;int type;} types[];在这里记录了全部类型和名称如({"void",QMetaType::Void});Void在Qmetatype.h中定义。

 

 

[cpp]  view plain copy
  1. QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);  


调用QMetaObject的connect函数,再次不详细写出。

 

[cpp]  view plain copy
  1. const_cast<QObject*>(sender)->connectNotify(signal - 1);  


最后调用虚函数connectNotify表示connect已经执行完成。


这篇关于QT QObject::connect函数的学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1019634

相关文章

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

MySQL中FIND_IN_SET函数与INSTR函数用法解析

《MySQL中FIND_IN_SET函数与INSTR函数用法解析》:本文主要介绍MySQL中FIND_IN_SET函数与INSTR函数用法解析,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一... 目录一、功能定义与语法1、FIND_IN_SET函数2、INSTR函数二、本质区别对比三、实际场景案例分