QT中关于信号与槽机制的实现原理
2009-10-14 14:34
861 查看
一:
[
每个对象
]
都有一个相应的纪录该对象的
[
元对象
]
关于元对象的类:
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;
}
}
}
}
[
每个对象
]
都有一个相应的纪录该对象的
[
元对象
]
关于元对象的类:
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;
}
}
}
}
相关文章推荐
- QT中关于信号与槽机制的实现原理
- QT中关于信号与槽机制的实现原理
- QT中关于信号与槽机制的实现原理
- QT中关于信号与槽机制的实现原理
- QT中关于信号与槽机制的实现原理
- QT信号与槽机制的实现原理
- qt 信号,槽及反射机制的实现原理 (记录 gui programing with qt 4)
- 回调函数实现类似QT中信号机制
- Qt信号槽机制的实现(面试的感悟,猜测每一个类保存的一个信号和槽的二维表,实际使用函数指针 元对象 还有类型安全的检查设定等等)
- C++11实现Qt的信号槽机制
- 零基础学Qt4编程之Qt核心机制与原理之信号与槽
- theoretical-零基础学Qt4编程之Qt核心机制与原理之信号与槽-
- QT中采用信号槽机制实现两个label切换图片的关联
- Qt信号与槽实现原理
- theoretical-零基础学Qt4编程之Qt核心机制与原理之信号与槽-
- QT中采用信号槽机制实现两个label切换图片的关联
- 【QT】深入qt信号与槽实现原理
- 关于qt的信号槽机制的理解 分类: QT学习记录 2011-09-23 11:22 1872人阅读 评论(1) 收藏
- 零基础学Qt4编程之Qt核心机制与原理之信号与槽
- Java实现Qt的SIGNAL-SLOT机制(保存到Map中,从而将它们关联起来,收到信号进行解析,最后反射调用)