1. 程式人生 > >Qt中的connect函式使用

Qt中的connect函式使用

我們在使用connect函式的時候一般是這樣呼叫的:

  1. connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));  

這裡用到了兩個巨集:SIGNAL() 和SLOT();通過connect宣告可以知道這兩個巨集最後倒是得到一個const char*型別。
在qobjectdefs.h中可以看到SIGNAL() 和SLOT()的巨集定義:

  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()"。

  1. connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));  
  2. 實際上就是connect(sender,“2signal()”,receiver,“1slot())”;  

搞明白了實際的引數就可以來看connect的真正實現過程了,在QObject.cpp檔案中可以找到connect的實現程式碼。

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

上面是去除了debug程式碼的connect實現。

  1. constvoid *cbdata[] = { sender, signal, receiver, method, &type };  
  2. if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))  
  3.       returntrue;  

判斷連線是否已經建立。
QInternal::ConnectCallback在qglobal.cpp中實現。

  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.     QInternal_CallBackTable *cbt = global_callback_table();  
  5.     if (cbt && cb < cbt->callbacks.size()) {  
  6.         QList<qInternalCallback> callbacks = cbt->callbacks[cb];  
  7.         bool ret = false;  
  8.         for (int i=0; i<callbacks.size(); ++i)  
  9.             ret |= (callbacks.at(i))(parameters);  
  10.         return ret;  
  11.     }  
  12.     returnfalse;  
  13. }  

QInternal_CallBackTable 定義為(qglobal.cpp)

  1. struct QInternal_CallBackTable {  
  2.     QVector<QList<qInternalCallback> > callbacks;  
  3. };  

qInternalCallback定義為(qnamespace.h)

  1. typedefbool (*qInternalCallback)(void **);這是一個函式指標 返回值是bool,只有一個引數為void**。這個指標在呼叫registerCallback加入列表。  
  1. if (!check_signal_macro(sender, signal, "connect""bind"))  
  2.     returnfalse;  

判斷signal是否合法。

在QObject.cpp檔案中可以找到check_signal_macro的實現

  1. staticbool check_signal_macro(const QObject *sender, constchar *signal,  
  2.                                 constchar *func, constchar *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.         returnfalse;  
  13.     }  
  14.     returntrue;  
  15. }  


extract的實現也在QObject中,它就是去字串第一個字元,並且只取低2位的值。