QT中關(guān)于信號(hào)與槽機(jī)制的實(shí)現(xiàn)原理,,需要用到的類,,在本文中一一展現(xiàn),,代碼較多,,內(nèi)容如下:
一,、每個(gè)對(duì)象都有一個(gè)相應(yīng)的紀(jì)錄該對(duì)象的元對(duì)象
關(guān)于元對(duì)象的類:
QMetaObject類:
- /*******************生成元對(duì)象需要的輸入?yún)?shù)*****************/
- //類名
- const char * const class_name,
- //父類名
- QMetaObject *superclass,
- //記錄slot 信息
- const QMetaData * const slot_data,
- //記錄槽的個(gè)數(shù)
- int n_slots,
- //記錄signal 信息
- const QMetaData * const signal_data,
- //記錄信號(hào)的個(gè)數(shù)
- int n_signals
- /******************* 元對(duì)象類提供的方法**************************/
- int numSlots( bool super = FALSE ) const;//返回槽的個(gè)數(shù)
- int numSignals( bool super = FALSE ) const;//返回信號(hào)的個(gè)數(shù)
- int findSlot( const char *, bool super = FALSE ) const;//查找槽
- int findSignal( const char *, bool super = FALSE ) const;//查找信號(hào)
- //返回指定位置的槽
- const QMetaData *slot( int index, bool super = FALSE ) const;
- //返回指定位置的信號(hào)
- const QMetaData *signal( int index, bool super = FALSE ) const;
- //所有槽名字的列表
- QStrList slotNames( bool super = FALSE ) const;
- //所有信號(hào)名字的列表
- QStrList signalNames( bool super = FALSE ) const;
- //槽的起始索引
- int slotOffset() const;
- //信號(hào)的起始索引
- int signalOffset() const;
- /***********************兩個(gè)獲取類的元對(duì)象的方法*****************/
- static QMetaObject *metaObject( const char *class_name );
- static bool hasMetaObject( const char *class_name );
QMetaData類:
- //記錄元對(duì)象數(shù)據(jù)for 信號(hào)與槽
- struct QMetaData
- {
- const char *name; //名稱
- const QUMethod* method; //詳細(xì)描述信息
- enum Access { Private, Protected, Public };
- Access access; //訪問(wèn)權(quán)限
- };
二,、QObject類實(shí)現(xiàn)了信號(hào)與槽機(jī)制
它利用元對(duì)象紀(jì)錄的信息,,實(shí)現(xiàn)了信號(hào)與槽機(jī)制
(1)信號(hào)與槽建立連接的實(shí)現(xiàn)
接口函數(shù):
- //連接
- //參數(shù)(發(fā)送對(duì)象,,信號(hào),,接收對(duì)象,,處理信號(hào)的信號(hào)/槽)
- 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 );
- //連接的內(nèi)部實(shí)現(xiàn)
- //(發(fā)送對(duì)象,信號(hào)的索引,,接收對(duì)象,,處理信號(hào)的類型,處理信號(hào)信號(hào)/槽的索引)
- 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 );
信號(hào)與槽連接的實(shí)現(xiàn)原理:
- ①階段
- bool QObject::connect( const QObject *sender,//發(fā)送對(duì)象
- const char *signal,//信號(hào)
- const QObject *receiver, //接收對(duì)象
- const char *member //槽
- )
- {
- //檢查發(fā)送對(duì)象,,信號(hào),,接收對(duì)象,槽不為null
- if ( sender == 0 || receiver == 0 || signal == 0 || member == 0 ) {
- return FALSE;
- }
- //獲取發(fā)送對(duì)象的元對(duì)象
- QMetaObject *smeta = sender->metaObject();
- //檢查信號(hào)
- if ( !check_signal_macro( sender, signal, "connect", "bind" ) )
- return FALSE;
- //獲取信號(hào)的索引
- 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 );
- }
- //如果信號(hào)不存在,,則退出
- if ( signal_index < 0 ) { // no such signal
- return FALSE;
- }
- //獲取信號(hào)的元數(shù)據(jù)對(duì)象
- const QMetaData *sm = smeta->signal( signal_index, TRUE );
- //獲取信號(hào)名字
- signal = sm->name;
- //獲取處理信號(hào)的類型(是信號(hào)/槽)
- int membcode = member[0] - '0'; // get member code
- //發(fā)送信號(hào)對(duì)象
- QObject *s = (QObject *)sender; // we need to change them
- //接收信號(hào)對(duì)象
- QObject *r = (QObject *)receiver; // internally
- //獲取接收對(duì)象的元對(duì)象
- QMetaObject *rrmeta = 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://如果是信號(hào)
- //獲取信號(hào)索引
- 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;
- }
- /如果接收對(duì)象不存在相應(yīng)的信號(hào)或槽,,則退出
- if ( member_index < 0 ) {
- return FALSE;
- }
- //檢查連接的參數(shù)(發(fā)送的信號(hào),接收對(duì)象,,處理信號(hào)的槽或信號(hào))
- if ( !s->checkConnectArgs(signal,receiver,member) ) {
- return FALSE;
- } else {
- //獲取處理信號(hào)的元數(shù)據(jù)對(duì)象
- const QMetaData *rm = membcode == QSLOT_CODE ?
- rmeta->slot( member_index, TRUE ) :
- rmeta->signal( member_index, TRUE );
- if ( rm ) {
- //建立連接
- //(發(fā)送信號(hào)的對(duì)象,,信號(hào)的索引,接收信號(hào)的對(duì)象,,
- 處理信號(hào)的類型,,處理信號(hào)的索引)
- connectInternal( sender, signal_index, receiver, membcode, member_index );
- }
- }
- return TRUE;
- }
- ②階段
- //建立連接
- //(發(fā)送信號(hào)的對(duì)象,信號(hào)的索引,,接收信號(hào)的對(duì)象,,處理信號(hào)的類型,處理信號(hào)的索引)
- void QObject::connectInternal( const QObject *sender, int signal_index,
- const QObject *receiver, int membcode, int member_index )
- {
- //發(fā)送信號(hào)的對(duì)象
- QObject *s = (QObject*)sender;
- //接收信號(hào)的對(duì)象
- QObject *r = (QObject*)receiver;
- //如果發(fā)送對(duì)象的連接查詢表為null,,則建立
- if ( !s->connections ) { // create connections lookup table
- s->connections = new QSignalVec( signal_index+1 );
- Q_CHECK_PTR( s->connections );
- s->connections->setAutoDelete( TRUE );
- }
- //獲取發(fā)送對(duì)象的相應(yīng)信號(hào)的連接列表
-
- 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 *rrmeta = 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 );
- //把連接添加到發(fā)送對(duì)象的連接列表中
- clist->append( c );
- //判斷接收對(duì)象的發(fā)送對(duì)象列表是否為null
- if ( !r->senderObjects ) // create list of senders
- {
- //建立接收對(duì)象的發(fā)送對(duì)象列表
- r->senderObjects = new QSenderObjectList;
- }
- //把發(fā)送對(duì)象添加到發(fā)送對(duì)象列表中
- r->senderObjects->append( s ); // add sender to list
- }
(2)信號(hào)發(fā)生時(shí)激活的操作函數(shù),。 激活slot的方法
接口: - void QObject::activate_signal( int signal )
- {
- #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY
- if ( qt_preliminary_signal_spy ) {
- //信號(hào)沒(méi)有被阻塞
- //信號(hào)>=0
- //連接列表不為空,或者信號(hào)對(duì)應(yīng)的連接存在
- 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;
- //獲取信號(hào)對(duì)應(yīng)的連接列表
- QConnectionList *clist = connections->at( signal );
- if ( !clist )
- return;
- QUObject o[1];
- //
- activate_signal( clist, o );
- }
-
- 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;
- //發(fā)送對(duì)象列表
- QSenderObjectList* sol;
- //舊的發(fā)送對(duì)象
- QObject* oldSender = 0;
- //連接
- QConnection *c;
- if ( clist->count() == 1 ) { // save iterator
- //獲取連接
- c = clist->first();
- //
- object = c->object();
- //獲取發(fā)送對(duì)象列表
- sol = object->senderObjects;
- if ( sol ) {
- //獲取舊的發(fā)送對(duì)象
- oldSender = sol->currentSender;
- //
- sol->ref();
- //設(shè)置新的發(fā)送對(duì)象
- sol->currentSender = this;
- }
- if ( c->memberType() == QSIGNAL_CODE )//如果是信號(hào),,則發(fā)送出去
- object->qt_emit( c->member(), o );
- else
- object->qt_invoke( c->member(), o );//如果是槽,,則執(zhí)行
- //
- if ( sol ) {
- //設(shè)置恢復(fù)為舊的發(fā)送對(duì)象
- sol->currentSender = oldSender;
- if ( sol->deref() )
- delete sol;
- }
- } else {
- QConnection *cd = 0;
- QConnectionListIt it(*clist);
- while ( (c=it.current()) ) {
- ++it;
- if ( c == cd )
- continue;
- ccd = c;
- object = c->object();
- //操作前設(shè)置當(dāng)前發(fā)送對(duì)象
- sol = object->senderObjects;
- if ( sol ) {
- oldSender = sol->currentSender;
- sol->ref();
- sol->currentSender = this;
- }
- //如果是信號(hào),則發(fā)送出去
- if ( c->memberType() == QSIGNAL_CODE ){
- object->qt_emit( c->member(), o );
- }
- //如果是槽,,則執(zhí)行
- else{
- object->qt_invoke( c->member(), o );
- }
- //操作后恢復(fù)當(dāng)前發(fā)送對(duì)象
- if (sol ) {
- sol->currentSender = oldSender;
- if ( sol->deref() )
- delete sol;
- }
- }
- }
- }
【編輯推薦】
Qt的插件機(jī)制
QT的信號(hào)與槽機(jī)制
Qt網(wǎng)絡(luò)之獲取本機(jī)網(wǎng)絡(luò)信息
淺談自動(dòng)化測(cè)試工具 QTP腳本的重用
Qt和KDE在未來(lái)將面臨新的挑戰(zhàn)和機(jī)遇
|