QT 信号和槽式如何实现的

[复制链接]
查看11 | 回复1 | 2011-3-29 08:07:38 | 显示全部楼层 |阅读模式
回复

使用道具 举报

千问 | 2011-3-29 08:07:38 | 显示全部楼层
<pre id=\"best-answer-content\" class=\"reply-text mb10\">一: [ 每个对象 ] 都有一个相应的纪录该对象的 [ 元对象 ]
关于元对象的类:
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;

// 所有槽名字的列表

QStrListslotNames( bool super = FALSE ) const;

// 所有信号名字的列表

QStrListsignalNames( 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 boolconnect( 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 booldisconnect( 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_index0 ) {
// 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_index0) {
// 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_index0 ) {
// 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_index0 ) {
// normalize and retry

nw_member = qt_rmWS(member);
// remove whitespace

member = nw_member;

member_index = rmeta-findSignal( member, TRUE );

}

break;

}

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

if ( member_index0) {

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() = 0 at( signal ) ) ) {

//

QUObject o[1];

qt_spy_signal( this, signal, o );

return;

}

}

#endif


if ( !connections || signalsBlocked() || signal0 )

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;

}

}

}
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行