QT中关于信号与槽机制的实现原理是什么?
QT中关于信号与槽机制的实现原理是什么?
[QT中关于信号与槽机制的实现原理.]
[tan.zhenhua]
一:[每个对象]都有一个相应的纪录该对象的[元对象]
关于元对象的类:
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 );