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,里面有类似的实现,机制是一样的。