一:信号槽是什么?

Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的说法,简单点说就是如何在一个类的一个函数中触发另一个类的另一个函数调用,而且还要把相关的参数传递过去.好像这和回调函数也有点关系,但是消息机制可比回调函数有用

二:Qt支持三种类型的信号-槽连接:
1,直接连接,当signal发射时,slot立即调用。此slot在发射signal的那个线程中被执行(不一定是接收对象生存的那个线程)
2,队列连接,当控制权回到对象属于的那个线程的事件循环时,slot被调用。此slot在接收对象生存的那个线程中被执行
3,自动连接(缺省),假如信号发射与接收者在同一个线程中,其行为如直接连接,否则,其行为如队列连接。
连接类型可能通过以向connect()传递参数来指定。注意的是,当发送者与接收者生存在不同的线程中,而事件循环正运行于接收者的线程中,使用直接连接是不安全的。同样的道理,调用生存在不同的线程中的对象的函数也是不是安全的。QObject::connect()本身是线程安全的。

用Qt写Gui程序的时候,在main函数里面最后依据都是app.exec();很多书上对这句的解释是,使Qt程序进入消息循环。  

当前connectionType为Qt::AutoConnection并且signal和slot不在一个线程或者是signal和不再当前线程中;或者是c->connectionType为 Qt::QueuedConnection这时候调用函数queued_activate:对参数转换一下,然后调用QCoreApplication::postEvent
注意: postEvent第二个参数是QMetaCallEvent。
这样这个signal-slot的connection就发送到receiver的消息队列中去了。 

三:connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 
这里用到了两个宏:SIGNAL() 和SLOT();通过connect声明可以知道这两个宏最后倒是得到一个const char*类型
在qobjectdefs.h中可以看到SIGNAL() 和SLOT()的宏定义:

#ifndef QT_NO_DEBUG 
# define QLOCATION "\0"__FILE__":"QTOSTRING(__LINE__) 
# define METHOD(a)   qFlagLocation("0"#a QLOCATION) 
# define SLOT(a)     qFlagLocation("1"#a QLOCATION) 
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION) 
#else 
# define METHOD(a)   "0"#a 
# define SLOT(a)     "1"#a 
# define SIGNAL(a)   "2"#a 
#endif 
所以这两个宏的作用就是把函数名转换为字符串并且在前面加上标识符

比如:SIGNAL(read())展开后就是"2read()";同理SLOT(read())展开后就是"1read()"。

connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 
实际上就是connect(sender,“2signal()”,receiver,“1slot())”; 

四:

# if defined(QT_NO_KEYWORDS)
#  define QT_NO_EMIT
# else
#   define slots
#   define signals protected
# endif
# define Q_SLOTS
# define Q_SIGNALS protected
# define Q_PRIVATE_SLOT(d, signature)
# define Q_EMIT
#ifndef QT_NO_EMIT
# define emit
#endif

signals宏有点不同,它限定Qt信号为protected方法,而slots宏可以是任意类型。

头文件定义的public slots和signals对C++编译器而言没有意义,会被替换成public和protected。他们的真实意图其实是给moc工具使用的,moc根据这些字符串关键字匹配,用来生成文件moc_Counter.cppQt源码的构建过程是先moc转换然后再执行C++编译器。moc的目的是展开信号和槽,生成一个能让编译器读懂的源文件

五:MOC元数据

Q_OBJECT创建QMetaObejct元对象数据成员:用来做信号槽的二维表。对于某一个信号,在二维表中存放着这个信号对应的槽的函数指针。依据这个信号的名字去查询二维表,找到对应的槽的函数指针并进行调用

Qt的信号槽机制其实就是按照名称查表,因此这里的首要问题是如何构造这个表?和C++虚函数表机制类似的,在Qt中,这个表就是元数据表

不过Qt似乎还没有完全发挥元数据的能力,动态属性,反射之类的机制

一般是通过宏Q_OBJECT定义的(内省函数
#define Q_OBJECT / 
public: / 
    static const QMetaObject staticMetaObject; / 
    virtual const QMetaObject *metaObject() const; / 
    virtual void *qt_metacast(const char *); / 
    QT_TR_FUNCTIONS / 
    virtual int qt_metacall(QMetaObject::Call, int, void **); / 
private:

这里的三个虚函数metaObject,qt_metacast,qt_metacall是在moc文件中定义的
staticMetaObject是 QMetaObject对象,因为需要给属于同一类的全部实例共享,所以它是静态的。得到元数据表指针
metaObject方法仅仅返回staticMetaObject。
QT_TR_FUNCTIONS是一个用于所有tr函数的宏,用来实现多语言支持。
qt_metacast用于按照类名或它的某个基类名 进行动态转换(dynamic cast)【Qt显然不依赖运行时类型检查(RTTI)】。
qt_metacall通过索引查表调用内部信号和槽参数由一个指向指针数组的指针进行传递,并在调用方法时进行适当的转换

用户设计的类可以从多个类派生,但只能拥有一个QObject(或从它派生)基类,这同时也是超类
class ConvDialog : public QDialog, private Ui::ConvDialog
{
    Q_OBJECT
Moc将产生以下代码:
const QMetaObject ConvDialog::staticMetaObject = {
    { &QDialog::staticMetaObject, qt_meta_stringdata_ConvDialog,
      qt_meta_data_ConvDialog, 0 }
};
如果在QDialog前先继承Ui::ConvDialog,moc将会生成:
const QMetaObject ConvDialog::staticMetaObject = {
    { &Ui::ConvDialog::staticMetaObject, qt_meta_stringdata_ConvDialog,
      qt_meta_data_ConvDialog, 0 }
};
这是错误的,因为Ui::ConvDialog不是QObject的一个派生类,由此不拥有staticMetaObject成员,这样做只会导致一个编译错误。

QMetaObject中的结构体d

struct{
        const QMetaObject *superdata;//这是元数据代表的类的基类的元数据
        const char *stringdata;//这是元数据的签名标记
        const uint *data;//这是元数据的索引数组的指针
        const QMetaObject **extradata;//这是扩展元数据表的指针,一般是不用的 
}d;

第一个参数:QMetaObject类指针,指向父Qt元数据类。

第三个参数:无符号整型数组,这个数组是一个表,包含所有元数据的偏移、特征等等。所以,如果你想枚举一个类的信号和槽,那就应该遍历这个表,通过偏移量从stringdata数组中获得方法名。

参考文章:http://blog.csdn.net/tingsking18/article/details/4991563

http://www.cnblogs.com/findumars/p/4851262.html

http://www.pediy.com/kssd/pediy12/133181.html

http://www.devbean.net/2012/12/how-qt-signals-and-slots-work/

QT信号槽连接的更多相关文章

  1. Qt——信号槽连接:基于字符串与基于函数的连接之间的不同

    从Qt5.0开始,Qt提供了两种不同的方式进行信号槽的连接:基于 字符串 的连接语法.基于 函数 的连接语法.这两种语法各有利弊,下面对它们的不同点进行总结. 以下几部分详细解释了它们之间的不同,并说 ...

  2. QT信号槽连接语法总结

    信号槽是 Qt 框架引以为豪的机制之一. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal).这种触发是没有目的的,类似广播.如果 ...

  3. Qt信号槽连接在有默认形参下的情况思考

    写下这个给自己备忘,比如函数 ) 你在调用端如论是test(3)或者test(),都可以正确调用到这个函数. 但是,如果放到Qt中的信号槽的话,这个还是值得讲一讲的,不然的话,可能会引起相应的误会. ...

  4. Qt信号槽的一些事(第一次知道信号还有返回值,以及Qt::UniqueConnection)

    注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...

  5. QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类

    一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如: QObject::connect: Can ...

  6. QT信号槽详解

    1         QT信号槽详解 1.1  信号和槽的定义 信号是触发信号,例如按钮的点击触发一个clicked信号,槽是用来接收信号,并处理信号,相当于信号响应函数.一个信号可以关联多个槽函数,信 ...

  7. Qt信号槽的一些事 Qt::带返回值的信号发射方式

    一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值.那么如果我们发出这个信号想获取一个返回值怎么办呢? 两个办法:1.通过出参形式返回,引用或者指 ...

  8. Qt信号槽的一些事

    注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...

  9. QT源码之Qt信号槽机制与事件机制的联系

    QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...

随机推荐

  1. MongoDB CRUD 操作

    crud是指在做计算处理时的增加(Create).读取查询(Retrieve).更新(Update)和删除(Delete)几个单词的首字母简写.crud主要被用在描述软件系统中数据库或者持久层的基本操 ...

  2. 欢迎使用CSDN的markdown编辑器

    以下是蒻鞫第一次打开CSDN-markdown编译器的温馨提示,感觉CSDN好贴心,不作任何用途,仅为纪念,若存在违法侵权行为,请联系留言,立即删除. List item 这里写 欢迎使用Markdo ...

  3. (转)Redis Cluster(集群)

    一.概述 在前面的文章中介绍过了redis的主从和哨兵两种集群方案,redis从3.0版本开始引入了redis-cluster(集群).从主从-哨兵-集群可以看到redis的不断完善:主从复制是最简单 ...

  4. dubbo+zookeeper示例记录

    提示:要直接看搭建例子的可以跳到 三 一.项目架构的发展 传统的mvc架构项目将整个系统功能实现全部写在一个项目中,部署在一个机器上,随着用户量的增涨,单个项目服务器无法承受暴增的用户请求时需要增加服 ...

  5. ros资料记录,详细阅读

    ROS源码分析--子话题-catkin:https://blog.csdn.net/sukha/article/details/52460492 ROS源码分析:https://blog.csdn.n ...

  6. BZOJ1941Hide and Seek

    做KD_tree的入门题. 问题就是求出任意一个点距其他点的最大曼哈顿距离和最小曼哈顿距离差,然后对其取min即可. 这个东西就是KD_tree可以轻松解决的了. 下面总结一下做KD_tree(不带修 ...

  7. Facebook开源时间序列内存数据库Beringei,追求极致压缩率——如果是int根据大多数时间序列中的值与相邻数据点相比并没有显著的变化,只要使用XOR将当前值与先前值进行比较,然后存储发生变化的比特。最终,该算法将整个数据集至少压缩了90%

    转自:http://www.infoq.com/cn/news/2017/02/Facebook-Beringei 2017年2月3日,Facebook宣布将开源他们的高性能时序数据存储引擎Berin ...

  8. Cross-Site Request Forgery (CSRF)

    https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) Overview Cross-Site Request Forger ...

  9. 数据库连接池配置(案例及排查指南) 原创: 有赞技术 有赞coder 4天前

    数据库连接池配置(案例及排查指南) 原创: 有赞技术 有赞coder 4天前

  10. pgpool-II 高可用搭建

    pgpool-II主备流复制的架设1.环境 OS: CentOS release 6.4 (Final)DB: postgresql 9.3.6pgpool服务器: pgpool 172.16.0.2 ...