QT中关于信号与槽机制的实现原理

news/2024/5/19 1:34:39 标签: qt, signal, whitespace, access, object, iterator

一: [ 每个对象 ] 都有一个相应的纪录该对象的 [ 元对象 ]

关于元对象的类:

QMetaObject 类:

                     /******************* 生成元对象需要的输入参数 *****************/

                     // 类名

                  const char * const class_name,

                  // 父类名

                  QMetaObject *superclass,

                  // 记录 slot 信息

                     const QMetaData * const slot_data,

                     // 记录槽的个数

                  int n_slots,

                     // 记录 signal 信息

                     const QMetaData * const signal_data,

                     // 记录信号的个数

                  int n_signals

                     /******************* 元对象类提供的方法 **************************/

                  int   numSlots( bool super = FALSE ) const;// 返回槽的个数

                  int   numSignals( bool super = FALSE ) const;// 返回信号的个数

                  int   findSlot( const char *, bool super = FALSE ) const;// 查找槽

                  int   findSignal( const char *, bool super = FALSE ) const;// 查找信号

                     // 返回指定位置的槽

                  const QMetaData *slot( int index, bool super = FALSE ) const;

                     // 返回指定位置的信号

                  const QMetaData *signal( int index, bool super = FALSE ) const;

                     // 所有槽名字的列表

                  QStrList  slotNames( bool super = FALSE ) const;

                     // 所有信号名字的列表

                  QStrList  signalNames( bool super = FALSE ) const;

                     // 槽的起始索引

                  int   slotOffset() const;

                     // 信号的起始索引

                  int   signalOffset() const;

                     /*********************** 两个获取类的元对象的方法 *****************/

                     static QMetaObject *metaObject( const char *class_name );

                  static bool hasMetaObject( const char *class_name );

QMetaData 类:

                     // 记录元对象数据 for 信号与槽

                     struct QMetaData        

                     {                                

                         const char *name;                       // 名称

                         const QUMethod* method;                // 详细描述信息

                         enum Access { Private, Protected, Public };

                         Access access;                            // 访问权限

                     };

二: [QObject 类实现了信号与槽机制 ]

       它利用元对象纪录的信息,实现了信号与槽机制

1 )信号与槽建立连接的实现

         接口函数:

              // 连接

              // 参数(发送对象,信号,接收对象,处理信号的信号 / 槽)

              static bool  connect( const QObject *sender, const char *signal,

                                           const QObject *receiver, const char *member );

           bool connect(const QObject *sender, const char *signal,

                                 const char *member ) const;

           static bool  disconnect( const QObject *sender, const char *signal,

                                             const QObject *receiver, const char *member );

           bool disconnect(const char *signal=0,

                                  const QObject *receiver=0, const char *member=0 );

           bool disconnect( const QObject *receiver, const char *member=0 );

              // 连接的内部实现

              // (发送对象,信号的索引,接收对象,处理信号的类型,处理信号信号 / 槽的索引)

           static void connectInternal(const QObject *sender, int signal_index,

                                                  const QObject *receiver, int membcode, int member_index );

           static bool disconnectInternal(const QObject *sender, int signal_index,

                                                const QObject *receiver, int membcode, int member_index );

       信号与槽连接的实现原理:

       阶段

       bool QObject::connect( const QObject *sender,// 发送对象      

                                        const char *signal,// 信号

                                   const QObject *receiver, // 接收对象

                                   const char *member //

                                 )

       {

              // 检查发送对象,信号,接收对象,槽不为 null

           if ( sender == 0 || receiver == 0 || signal == 0 || member == 0 ) {     

                     return FALSE;

           }

           // 获取发送对象的元对象

           QMetaObject *smeta = sender->metaObject();

              // 检查信号

           if ( !check_signal_macro( sender, signal, "connect", "bind" ) )

                     return FALSE;  

           // 获取信号的索引

           int signal_index = smeta->findSignal( signal, TRUE );

           if ( signal_index < 0 ) {                // normalize and retry

                     nw_signal = qt_rmWS( signal-1 ); // remove whitespace

                     signal = nw_signal.data()+1;         // skip member type code

                     signal_index = smeta->findSignal( signal, TRUE );

            }

           // 如果信号不存在,则退出

           if ( signal_index < 0  ) {                    // no such signal

                     return FALSE;

           }

           // 获取信号的元数据对象

            const QMetaData *sm = smeta->signal( signal_index, TRUE );

           // 获取信号名字

           signal = sm->name;      

              // 获取处理信号的类型(是信号 / 槽)

           int membcode = member[0] - '0';        // get member code

              // 发送信号对象

           QObject *s = (QObject *)sender;        // we need to change them

           // 接收信号对象

           QObject *r = (QObject *)receiver;             //   internally

           // 获取接收对象的元对象

           QMetaObject *rmeta = r->metaObject();

           int member_index = -1;

           switch ( membcode ) {                // get receiver member

                     case QSLOT_CODE:// 如果是槽

                            // 获取槽索引

                         member_index = rmeta->findSlot( member, TRUE );

                         if ( member_index < 0 ) {            // normalize and retry

                                   nw_member = qt_rmWS(member);     // remove whitespace

                                   member = nw_member;

                                   member_index = rmeta->findSlot( member, TRUE );

                         }

                         break;

                     case QSIGNAL_CODE:// 如果是信号

                            // 获取信号索引

                         member_index = rmeta->findSignal( member, TRUE );

                         if ( member_index < 0 ) {            // normalize and retry

                            nw_member = qt_rmWS(member);     // remove whitespace

                            member = nw_member;

                            member_index = rmeta->findSignal( member, TRUE );

                         }

                         break;

           }

           / 如果接收对象不存在相应的信号或槽,则退出

           if ( member_index < 0  ) {

                     return FALSE;

           }

              // 检查连接的参数 ( 发送的信号,接收对象,处理信号的槽或信号 )

           if ( !s->checkConnectArgs(signal,receiver,member) ) {

                     return FALSE;

           } else {

                // 获取处理信号的元数据对象

                     const QMetaData *rm = membcode == QSLOT_CODE ?

                                     rmeta->slot( member_index, TRUE ) :

                                     rmeta->signal( member_index, TRUE );

                          

                     if ( rm ) {         

                         // 建立连接

                            //( 发送信号的对象,信号的索引,接收信号的对象,

                                处理信号的类型,处理信号的索引 )

                         connectInternal( sender, signal_index, receiver, membcode, member_index );

                   }

              }

           return TRUE;

       }

       阶段

       // 建立连接

       //( 发送信号的对象,信号的索引,接收信号的对象,处理信号的类型,处理信号的索引 )

       void QObject::connectInternal( const QObject *sender, int signal_index,

                                                   const QObject *receiver,

                                           int membcode, int member_index )

       {

       // 发送信号的对象

    QObject *s = (QObject*)sender;

       // 接收信号的对象

    QObject *r = (QObject*)receiver;

 

    // 如果发送对象的连接查询表为 null ,则建立

    if ( !s->connections ) {                // create connections lookup table

       s->connections = new QSignalVec( signal_index+1 );

       Q_CHECK_PTR( s->connections );

       s->connections->setAutoDelete( TRUE );

    }

    // 获取发送对象的相应信号的连接列表

    QConnectionList *clist = s->connections->at( signal_index );

    if ( !clist ) {                         // create receiver list

       clist = new QConnectionList;

       Q_CHECK_PTR( clist );

       clist->setAutoDelete( TRUE );

       s->connections->insert( signal_index, clist );

    }

 

    QMetaObject *rmeta = r->metaObject();

    const QMetaData *rm = 0;

 

    switch ( membcode ) {                // get receiver member

       case QSLOT_CODE:

           rm = rmeta->slot( member_index, TRUE );

           break;

       case QSIGNAL_CODE:

           rm = rmeta->signal( member_index, TRUE );

           break;

    }

    // 建立连接

QConnection *c = new QConnection( r, member_index, rm ? rm->name :

                                                                      "qt_invoke", membcode );

    Q_CHECK_PTR( c );

    // 把连接添加到发送对象的连接列表中

    clist->append( c );

    // 判断接收对象的发送对象列表是否为 null

    if ( !r->senderObjects )               // create list of senders

           {

           // 建立接收对象的发送对象列表

       r->senderObjects = new QSenderObjectList;

           }

    // 把发送对象添加到发送对象列表中

    r->senderObjects->append( s );           // add sender to list

   

       }

2 )信号发生时激活的操作函数

       接口:

       /***************************************************************

       ** 激活 slot 的方法

       ****************************************************************/

       void QObject::activate_signal( int signal )

       {

       #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY

           if ( qt_preliminary_signal_spy ) {

                  // 信号没有被阻塞

                  // 信号 >=0

                  // 连接列表不为空,或者信号对应的连接存在

              if ( !signalsBlocked() && signal >= 0 &&

                 ( !connections || !connections->at( signal ) ) ) {

                 //

                  QUObject o[1];

                  qt_spy_signal( this, signal, o );

                  return;

              }

    }

       #endif

 

    if ( !connections || signalsBlocked() || signal < 0 )

       return;

    // 获取信号对应的连接列表

    QConnectionList *clist = connections->at( signal );

    if ( !clist )

       return;

    QUObject o[1];

    //

    activate_signal( clist, o );

}

 

/***************************************************************

** 激活 slot 的方法

****************************************************************/

void QObject::activate_signal( QConnectionList *clist, QUObject *o )

{

    if ( !clist )

       return;

 

#ifndef QT_NO_PRELIMINARY_SIGNAL_SPY

    if ( qt_preliminary_signal_spy )

       qt_spy_signal( this, connections->findRef( clist), o );

#endif

 

    QObject *object;

       // 发送对象列表

    QSenderObjectList* sol;

       // 旧的发送对象

    QObject* oldSender = 0;

       // 连接

    QConnection *c;

    if ( clist->count() == 1 ) { // save iterator

           // 获取连接

       c = clist->first();

       //

       object = c->object();

       // 获取发送对象列表

       sol = object->senderObjects;

       if ( sol ) {

              // 获取旧的发送对象

           oldSender = sol->currentSender;

              //

           sol->ref();

              // 设置新的发送对象

           sol->currentSender = this;

       }

      

       if ( c->memberType() == QSIGNAL_CODE )// 如果是信号,则发送出去

           object->qt_emit( c->member(), o );

       else

           object->qt_invoke( c->member(), o );// 如果是槽,则执行

 

       //    

       if ( sol ) {

              // 设置恢复为旧的发送对象

           sol->currentSender = oldSender;

           if ( sol->deref() )

              delete sol;

       }

    } else {

       QConnection *cd = 0;

       QConnectionListIt it(*clist);

       while ( (c=it.current()) ) {

           ++it;

           if ( c == cd )

              continue;

           cd = c;

           object = c->object();

           // 操作前设置当前发送对象

           sol = object->senderObjects;

           if ( sol ) {

              oldSender = sol->currentSender;

              sol->ref();

              sol->currentSender = this;

           }

 

 

           // 如果是信号,则发送出去

           if ( c->memberType() == QSIGNAL_CODE ){

              object->qt_emit( c->member(), o );

           }

           // 如果是槽,则执行

           else{

              object->qt_invoke( c->member(), o );

           }

          

           // 操作后恢复当前发送对象

           if (sol ) {

              sol->currentSender = oldSender;

              if ( sol->deref() )

                  delete sol;

           }

       }

    }

}


http://www.niftyadmin.cn/n/1139137.html

相关文章

python怎么打开h5文件_用Python打开.h5文件

我正在尝试用Python读取h5文件。 该文件可以在this link中找到&#xff0c;名为“vstoxx_data_31032014.h5”。我试图运行的代码来自Yves Hilpisch的《Python for Finance》一书&#xff0c;内容如下&#xff1a;import pandas as pd h5 pd.HDFStore(path.../vstoxx_data_3103…

关于QT的打印相关

void QCurveQueryTool::printview() //printFlag 2 , 打印预览{ QPrinter printer(QPrinter::ScreenResolution); QPrintPreviewDialog preview(&printer, this); preview.setMinimumSize(1000,900); connect(&preview, SIGNAL(paintRequested(QPrinter …

用什么技术实现前台页面设计_Java程序员最常用的20%技术总结

我听说编程语言&#xff0c;经常使用的是其中20&#xff05;的技术。在Java这门语言中&#xff0c;这20&#xff05;包括哪些内容&#xff1f;找到一份Java初级程序员的工作&#xff0c;有哪些是必须掌握的&#xff0c;有哪些是可以现学现卖的&#xff1f;一个完整的Javaweb项目…

QT表格相关

void QCurveQueryTool::printview() //printFlag 2 , 打印预览{ QPrinter printer(QPrinter::ScreenResolution); QPrintPreviewDialog preview(&printer, this); preview.setMinimumSize(1000,900); connect(&preview, SIGNAL(paintRequested(QPrinter …

python版本分类及区别_python2.x和python3.x的版本区别

Python 3.x 版本相对于Python的早期版本&#xff0c;是一个较大的升级&#xff1b;许多针对早期Python版本设计的程式都无法在Python 3.0上正常执行。 Python 3.0 的变化主要体现在以下几个方面&#xff1a; 1. print()函数 Python 2 中的print语句没有了&#xff0c;取而代之的…

Qt中的线程支持

Qt对线程提供了支持&#xff0c;基本形式有独立于平台的线程类、线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法。 警告&#xff1a;所有的GUI类&#xff08;比如&#xff0c;QWidget和它的子类&#xff09;&#xff0c;操作系统核心类&#xf…

finereport 登录界面的代码文件_【MMORPG开发日志04】登录注册场景前端制作完成

写在前面之前的文章我们通过实现简单的登录效果来大概的学习了一下KBEngine服务器引擎的原理以及前后端通信的过程。但既然是最游戏&#xff0c;我们一定是希望做出更漂亮的效果来的。所以这一节我们将前端场景优化一下。素材是我之前在&#xff08;泰课在线不用给我打钱了&…

高端人才必看,生意人必读!

1、人生最重要的不是努力&#xff0c;不是奋斗&#xff0c;而是抉择。 2、老板只能给一个位置&#xff0c;不能给一个未来。舞台再大&#xff0c;人走茶凉。 3、意外和明天不知道哪个先来。没有危机是最大的危机&#xff0c;满足现 状是最大的陷阱。 4、所见所闻改变一生&#…