qt信號槽機制原理
① qt的信號和槽是通過操作系統實現的嗎
一: [ 每個對象 ] 都有一個相應的紀錄該對象的 [ 元對象 ]
關於元對象的類:
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 信號和槽式如何實現的
一: [ 每個對象 ] 都有一個相應的紀錄該對象的 [ 元對象 ]
關於元對象的類:
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的信號槽機制,如果一個信號所連接的槽函數執行完之前,這個信號又被emit了,會發生什麼
執行完 在 執行一次
信號函數的實現在MOC 文件中,自動生成的。。其實就是 去 一個列表找專 相應的槽函數 執行
你發兩個信屬號 槽函數執行兩次。。。
加個標記 ,控制下 不然 會出問題
bool slotIsRuning
myslot(){
slotIsRuning = ture
.......
slotIsRuning = false
}
........
if(!slotIsRuning )
emit MySignal();
④ 如何用c++模擬qt 信號和槽機制
說明:
寫一個測試程序測試qml和c++利用信號槽機制傳輸信息.
測試程序功能版:16進制和10進制互相轉換權.
源代碼:
main.cpp
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <qtgui qguiapplication="">
#include qtquick2applicationviewer.h
#include <qtqml qqmlcontext="">
#include <qtquick qquickitem="">
#include <qtquick qquickview="">
#include myclass.h
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
MyClass my;
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStrin
⑤ 什麼是QT中的信號插槽機制
一、信號槽的基本概念
關於QT信號槽的基本概念大家都懂,通過信號槽機制,QT使對象間的通信變得非常簡單:
A對象聲明信號(signal),B對象實現與之參數相匹配的槽(slot),通過調用connect進行連接,合適的時機A對象使用emit把信號帶上參數發射出去,B對象的槽會就接收到響應。
信號槽機制有一些特點:
1. 類型安全:只有參數匹配的信號與槽才可以連接成功(信號的參數可以更多,槽會忽略多餘的參數)。
2. 線程安全:通過藉助QT自已的事件機制,信號槽支持跨線程並且可以保證線程安全。
3. 松耦合:信號不關心有哪些或者多少個對象與之連接;槽不關心自己連接了哪些對象的哪些信號。這些都不會影響何時發出信號或者信號如何處理。
4. 信號與槽是多對多的關系:一個信號可以連接多個槽,一個槽也可以用來接收多個信號。
使用這套機制,類需要繼承QObject並在類中聲明Q_OBJECT。下面就對信號槽的實現做一些剖析,了解了這些在使用的時候就不會踩坑嘍。
二、信號與槽的定義
槽:用來接收信號,可以被看作是普通成員函數,可以被直接調用。支持public,protected,private修飾,用來定義可以調用連接到此槽的范圍。
1. public slots:
2. void testslot(const QString& strSeqId);
信號:只需要聲明信號名與參數列表即可,就像是一個只有聲明沒有實現的成員函數。
1. signals:
2. void testsignal(const QString&);
QT會在moc的cpp文件中實現它(參考下面代碼)。下面代碼中調用activate的第三個參數是類中信號的序列號。
1. // SIGNAL 0
2. void CTestObject:: testsignal (const QString & _t1)
3. {
4. void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
5. QMetaObject::activate(this, &staticMetaObject, 0, _a);
6. }
三、信號槽的連接與觸發
通過調用connect()函數建立連接,會把連接信息保存在sender對象中;調用desconnect()函數來取消。
connect函數的最後一個參數來用指定連接類型(因為有默認,我們一般不填寫),後面會再提到它。
1. static bool connect(const QObject *sender, const QMetaMethod &signal,
2. const QObject *receiver, const QMetaMethod &method,
3. Qt::ConnectionType type = Qt::AutoConnection);
一切就緒,發射!在sender對象中調用:
1. emit testsignal(「test」);
1. # define emit
上面代碼可以看到emit被定義為空,這樣在發射信號時就相當於直接調用QT為我們moc出來的函數testsignal(constQString & _t1)。
具體的操作由QMetaObject::activate()來處理:遍歷所有receiver並觸發它們的slots。針對不同的連接類型,這里的派發邏輯會有不同。
更多信息請參閱:
http://blog.csdn.net/harbinzju/article/details/10813635
⑥ 什麼是信號槽深入理解信號槽
第3頁 兩個不同的術語以及各自的動作:信號和槽兩個不同的術語以及各自的動作:信號和槽;
在一個地方(信號)可以連接零個或者多個回調函數(槽),同時也是多對多的;
焦點在於連接本身,而不是提供者或者消費者;
不需要手工為了一個連接創建新的類;
連接仍舊是類型安全的。
這五點是信號槽系統的核心,Qt 和 boost 都擁有這些特性。下面則是二者的不同之處:
Boost.Signals
Qt Signals 和 Slots
一個信號就是一個對象 信號是具有名字的成員函數的簽名
發出信號類似於函數調用 發出信號類似於函數調用,Qt 提供了一個 emit 關鍵字來完成這個操作
信號可以是全局的、局部的或者是成員對象 信號只能是成員函數
任何能夠訪問到信號對象的代碼都可以發出信號 只有信號的擁有者才能發出信號
槽是任何可被調用的函數或者函數對象 槽是經過特別設計的成員函數
可以有返回值,返回值可以在多個槽中使用 沒有返回值
同步的 同步的或者隊列的
非線程安全 線程安全,可以跨線程使用
當且僅當槽是可追蹤的時候,槽被銷毀時,連接自動斷開 槽被銷毀時,連接都會自動斷開(因為所有槽都是可追蹤的)
類型安全(編譯器檢查) 類型安全(運行期檢查)
參數列表必須完全一致 槽可以忽略信號中多餘的參數
信號、槽可以是模板 信號、槽不能是模板
C++ 直接實現 通過由 moc 生成的元對象實現(moc 以及元對象系統都是 C++ 直接實現的)
沒有內省機制 可以通過內省發現
可以通過元對象調用
連接可以從資源文件中自動推斷出
最重要的是,Qt 的信號槽機制已經深深地植入到框架之中,成為不可分割的一部分。它們可以使用 Qt 專門的開發工具,例如 QtCreator,通過拖拽的方式很輕松的創建、刪除、修改。它們甚至可以通過動態載入資源文件,由特定命名的對象自動動態生成。這些都是 boost 作為一個通用庫所不可能提供的。
⑦ 怎麼理解QT中的信號與槽
對,信號可以自己定義
而信號一般是只聲明函數體,關鍵是其參數
信號一般是用來傳參或者是一種邏輯的調用者
信號的發射可以在你自定義的函數中
就比如我們繼承了一個widget,要重寫mousePressEvent
於是我們就可以自己定義一個signal, MyClicked( const QPoint& pos )
然後在事件中emit( MyClicked( event->pos() ) )
不過一般clicked信號是在mouseReleaseEvent中emit的
當然這一切都必須你繼承QObject以及聲明Q_OBJECT了
而且你也可以把你自己的一些屬性property聲明至元系統
就是宏Q_PROPERTY(...)
這個其實很有用,舉個例子
我們想知道信號發送者的某一個屬性
於是我已經Connect了
然後我們就可以在對應的槽中獲取
用sender()獲取object對象然後調用property來獲取發送者的某個屬性
還是自己多運用吧
以上都我自己打的阿~ 你還有不會的可以hi我
⑧ qt 事件機制和槽信號機制的區別
事件是不啟用了會自動上報信息,
信號時系統程序運行時發觸發了,會發送這個信號,但是如果你不關聯的話,這個信號就沒有意義了。
信號必須配合槽函數才能使用,而事件不需要。
⑨ Qt 信號槽機制與MFC中的句柄有什麼區別
應該問 Qt 信號槽機制 和 MFC 中的回調機制的區別吧.
⑩ Qt編程中信號與槽機制可以用什麼方法替換
QT的信號與槽機制,本身就是一種實現,如果你想使用其它機制,不知道你的具體需求,可能無法說的准確,可以試試消息通知機制(也是一種非同步回調,但是基於介面的,沒有信號槽那麼靈活),如果你是想使用信號/槽的其它實現,可以看看google的gtalk,裡面有類似的實現,機制是一樣的。