connect函数

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  

  1.     ) const;  
  2. 我们在使用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  

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


  3. [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中定义。

     

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值