信号与槽的connect连接函数

xiaoxiao2021-02-28  79

1 先理解一下信号与槽

我们通常会在改变一个组件的同时,通知另一个组件做出响应。改变一个组件的时候,就会发送一个信号,写好的槽会对这个信号进行匹配,做出相应的相应。

槽和信号都是函数,具有类成员函数相同的属性。唯一不同的就是槽可以与信号进行连接。这种通信方式是安全的,因为信号的函数签名必须与信号的函数签名匹配上。实际中,信号函数的参数可以比槽的参数多,因为槽可以自动忽略无用的参数。

2 connect 函数就是用来将信号与槽之间的联系建立起来的

2.1 格式:

QObject::connect(  发送方, signal(..), 接收方, slot(...))

源码出connect函数是这样定义的connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));  

SIGNAL,SLOT宏的作用是将信号和槽函数转化为字符串并添加标识符。

2.2 在使用connect函数需要注意到的问题

(1) 信号的发送者必须是QObject的派生对象。

(2) 槽函数所在类的定义中必须添加宏Q_OBJECT

(3) 如果槽函数是on_控件命_信号名,那么不需要主动调用connect进行连接

2.3 关于connect函数的实现

代码与注释如下

bool QObject::connect(const QObject *sender, const char *signal,                         const QObject *receiver, const char *method,                         Qt::ConnectionType type)   {       {           const void *cbdata[] = { sender, signal, receiver, method, &type };           if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))//判断连接是否已经建立               return true;       }          if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {           qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",                    sender ? sender->metaObject()->className() : "(null)",                    (signal && *signal) ? signal+1 : "(null)",                    receiver ? receiver->metaObject()->className() : "(null)",                    (method && *method) ? method+1 : "(null)");           return false;       }       QByteArray tmp_signal_name;          if (!check_signal_macro(sender, signal, "connect", "bind"))//判断信号是否合法         return false;       const QMetaObject *smeta = sender->metaObject();       const char *signal_arg = signal;       ++signal; //skip code       int signal_index = smeta->indexOfSignal(signal);       if (signal_index < 0) {           // check for normalized signatures           tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);           signal = tmp_signal_name.constData() + 1;              signal_index = smeta->indexOfSignal(signal);           if (signal_index < 0) {               err_method_notfound(sender, signal_arg, "connect");               err_info_about_objects("connect", sender, receiver);               return false;           }       } //获取signal的索引         QByteArray tmp_method_name;       int membcode = extract_code(method);          if (!check_method_code(membcode, receiver, method, "connect"))           return false;       const char *method_arg = method;       ++method; // skip code          const QMetaObject *rmeta = receiver->metaObject();       int method_index = -1;       switch (membcode) {       case QSLOT_CODE:           method_index = rmeta->indexOfSlot(method);           break;       case QSIGNAL_CODE:           method_index = rmeta->indexOfSignal(method);           break;       }       if (method_index < 0) {           // check for normalized methods           tmp_method_name = QMetaObject::normalizedSignature(method);           method = tmp_method_name.constData();           switch (membcode) {           case QSLOT_CODE:               method_index = rmeta->indexOfSlot(method);               break;           case QSIGNAL_CODE:               method_index = rmeta->indexOfSignal(method);               break;           }       }          if (method_index < 0) {           err_method_notfound(receiver, method_arg, "connect");           err_info_about_objects("connect", sender, receiver);           return false;       }       if (!QMetaObject::checkConnectArgs(signal, method)) { //判断signal和method是否兼容,通过判断其参数是否相同         qWarning("QObject::connect: Incompatible sender/receiver arguments"                    "\n        %s::%s --> %s::%s",                    sender->metaObject()->className(), signal,                    receiver->metaObject()->className(), method);           return false;       }          int *types = 0;       if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)               && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))           return false;          QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);       const_cast<QObject*>(sender)->connectNotify(signal - 1);  //调用虚函数connectNotify表示connect执行完成     return true;   }  

3 信号与槽通过connect函数连接的一个例子

//MyStr.h # ifndef  MYSTR # define  MYSTR #include<QObject> #include<QString>  class MyStr :public QObject{     Q_OBJECT //必须包含的宏  public:     MyStr (){m_value = "zero";}      QString value() const {return  m_value;}  public slots :     void setValue(QString value );      signals: //信号     void valueChanged(QString newValue);  private:     QString m_value; };  #endif 

#include"MyStr.h" void MyStr::setValue(QString value) {     if(value != m_value)//如果这里不进行判断,那么a,b信号就会重复调用,从而进入死循环     {         m_value = value;         emit valueChanged(value);     }

}

int main(int argc, char *argv[]) {     MyStr a;     MyStr b;     QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SLOT(setValue(QString)));     a.setValue("this is A");     return 0; }

当我们调用setValue函数时,将a.my_value设为了"this is A",也把信号valuechanged()发送了出去,被b.setValue接收,将b.my_value设为了"this is A",同时b又会把信号valuechanged发送出去,但此时因为没有建立连接所以没有接收者。

4 细节

一个信号可以连接多个槽

多个信号可以连接同一个槽

一个信号可以和另一个信号连接

QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SIGNAL(valueChanged(QString)));

连接是可以被删除的

QObject::disconnect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));

当连接的某一个对象被删除时,连接自动也就被删除了。

转载请注明原文地址: https://www.6miu.com/read-35157.html

最新回复(0)