QT中关于信号与槽机制的实现原理
2011-08-22 09:10
716 查看
QT中关于信号与槽机制的实现原理,需要用到的类,在本文中一一展现,代码较多,内容如下:
一、每个对象都有一个相应的纪录该对象的元对象
关于元对象的类:
QMetaObject类:
QMetaData类:
二、QObject类实现了信号与槽机制
它利用元对象纪录的信息,实现了信号与槽机制
(1)信号与槽建立连接的实现
接口函数:
信号与槽连接的实现原理:
(2)信号发生时激活的操作函数。 激活slot的方法
一、每个对象都有一个相应的纪录该对象的元对象
关于元对象的类:
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 *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://如果是信号 //获取信号索引 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 *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 ); //把连接添加到发送对象的连接列表中 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 ); } 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; ccd = 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的信号槽机制的理解
- 关于qt的信号槽机制的理解
- QT中采用信号槽机制实现两个label切换图片的关联
- 零基础学Qt4编程之Qt核心机制与原理之信号与槽
- C++11实现Qt的信号槽机制
- Qt信号槽机制的实现(面试的感悟,猜测每一个类保存的一个信号和槽的二维表,实际使用函数指针 元对象 还有类型安全的检查设定等等)
- 回调函数实现类似QT中信号机制
- 关于Qt信号与槽机制的传递方向性研究
- 零基础学Qt4编程之Qt核心机制与原理之信号与槽
- theoretical-零基础学Qt4编程之Qt核心机制与原理之信号与槽-
- QT中采用信号槽机制实现两个label切换图片的关联
- Qt核心机制与原理之信号与槽