QT源码分析-信号槽

信号槽基本概念

信号
当对象改变其状态时,信号就由改对象发射(emit)出去,而且对象只负责发送信号,它不知道另一端是谁在接收这个信号。


用于接收信号,而且槽只是普通的对象成员函数,一个槽并不知道是否有任何信号与自己相连。

信号与槽的连接
1、标准方式(QT5之前)

[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
  • 注意事项:
    将信号槽的函数名称按照相应规则组合成字符串,通过connect解析该字符串,分别获取信号槽的绝对索引,然后将信号槽的链接关系,添加到信号槽容器中。
    所有信号槽检查都在,运行时解析字符串的方式进行,即使字符串拼写错误也可以编译成功,创建的是空连接,在运行时报错。
  • 特性:
    不可以调用普通成员函数;
    支持使用重载信号和槽函数。
  • 链接类型:
    默认:Qt::AutoConnection,可手动设置。
  • 内部实现:
    QObject::connect。
    —·首选计算信号和槽的绝对索引;
    —·将其组合成相应的存储链接,存储到信号所对应的私有元对象中的信号槽存储容器中的指定位置;
    —·完成存储,并发送完成状态。

2、函数指针(QT5后方式)

[static] QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
  • 注意事项:
    编译时检查,使用函数指针作为信号槽函数。
  • 特性:
    可以调用普通成员函数、槽函数;
    不能定义两个重载信号函数,否则无法识别
    解决方案:
    1、static_cast<void(QComboBox::*)(int)>(&QComboBox::activated)
    2、QOverload::of(&QComboBox::activated)。
  • 链接类型:
    默认:Qt::AutoConnection,可手动设置。
  • 内部实现:
    template<typename Fun1, typename Fun2>
    static inline QMetaObject::Connect connect
    —·在一级调度(Object::connect)中分别获取信号和槽的数据特性,并存储到FunctionPoiter数据对象中;
    —·对其数据特征进行检查;
    —·检查完成,将信号和槽生成新的链接,并生成其对应的QSlotObject对象进行存储,并发送给二级调度(QObject::connctImpl)。
    —·二级调度对信号和槽进行检查,获取信号的绝对索引,发送给三级调度(QObjectPrivate::connctImpl)。
    —·标准流程数据操作一样。

3、Lambda表达式方式

connect(const QObject *sender, PointerToMemberFunction signal, [=](const int &arg){slot(arg)});
  • 注意事项:
    编译时检查,使用函数指针作为信号槽函数,lambda表达式返回的是槽函数的函数指针。
  • 特性:
    支持槽函数重载,不支持信号重载。
    解决方案:
    1、static_cast<void(QComboBox::*)(int)>(&QComboBox::activated)
    2、QOverload::of(&QComboBox::activated)。
  • 链接类型:
    默认:Qt::DirectConnection,不可手动设置。
  • 内部实现:
    template<typename Fun1, typename Fun2>
    static inline typename std::enable_if<QtPrivate::FunctionPointer::ArgumentCount==-1, QMetaObject::connection>::type
    connect
    —·与函数指针方式基本类似,唯一不同的就是连接方式指定为Qt::DirectConnection;存储槽函数的对象为QFunctorSlotObject对象。

Qt::ConnectionType常用值:

  1. Qt::AutoConnection(自动连接):(默认值)如果接收器位于发出信号的线程中,则使用Qt::DirectConnection。否则,将使用Qt::QueuedConnection。连接类型是在发出信号时确定的。
  2. Qt::DirectConnection(直接连接):在发出信号时会立即调用插槽。插槽在信号线程中执行。
  3. Qt::QueuedConnection(队列连接):当控制返回到接收器线程的事件循环时,将调用slot。插槽在接收器的线程中执行。
  4. Qt::UniqueConnection(独立连接):防止重复连接,如果当前信号和槽已经连接过滤,则不需要再连接。
  5. Qt::BlockingQueuedConnection(阻塞队列连接):同Qt::QueuedConnection类似,但是发送消息后阻塞,等到slot执行完。

MOC
the Meta Object Compiler。QT程序在交由标准编译器(eg:MSVC)编译之前,先使用moc分析cpp头文件;如果它发现在一个头文件中包含了Q_OBJECT宏,则会生成另外一个cpp源文件(moc_文件名.cpp),改cpp源文件包含了Q_OBJECT宏的实现、运行时信息(反射)等。
因此,QT程序的完成编译过称为moc->预编译->编译->汇编->链接->生成exe。

QT宏定义
信号槽相关的宏均定义在qobjectdefs.h文件中(位于QtCore目录)。

  • signals
    #define signals public
    则signals就相当于public

  • slots
    #define slots
    则slots就是空

  • Q_OBJECT

 #define Q_OBJECT \
public: \
    QT_WARNING_PUSH \
    Q_OBJECT_NO_OVERRIDE_WARNING \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
    QT_TR_FUNCTIONS \
private: \
    Q_OBJECT_NO_ATTRIBUTES_WARNING \
    Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    QT_WARNING_POP \
    struct QPrivateSignal {}; \
    QT_ANNOTATE_CLASS(qt_qobject, "")

则Q_OBJECT就相当于定义了一系列成员函数和成员变量

  • emit
    #define emit
    则emit就是空,无作用,只是比较友好的提示。

  • SLOT&SIGNAL

#ifndef QT_NO_META_MACROS
#ifndef QT_NO_DEBUG
# define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   qFlagLocation("0"#a QLOCATION)
# endif
# define SLOT(a)     qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)
#else
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   "0"#a
# endif
# define SLOT(a)     "1"#a
# define SIGNAL(a)   "2"#a
#endif

则SLOT相当于“1”#槽函数名
SIGNAL相当于“2”#信号名

所以,预处理之后的代码,就是将这些宏直接替换掉。

QT原对象系统(The Meta-Object System)

  • QT的原对象系统负责用于对象间通信的信号槽机制、运行时类型信息和属性系统(信号表、槽表、类信息表、属性表、指向父类的指针)。
  • 每个QObject子类都有一个唯一的QMetaObject实例,保存了这个QObject子类的所有元信息。
  • 可以通过metaObject()获取QMetaObject对象指针。
struct { // private data
        SuperData superdata;                      // 父类QMetaObject实例的指针
        const QByteArrayData *stringdata;  // 字符串内存,包含MetaObject信息的字符串信息
        const uint *data;                               // 包含MetaObject信息的索引表
        typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);   // 回调函数
        StaticMetacallFunction static_metacall;    // 回调函数
        const SuperData *relatedMetaObjects;
        void *extradata; //reserved for future use
    } d;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值