qt中实现息屏开平mousepress_QT信号槽分析

8a9b9da986a72c2da7d9565f52d6b5f5.png环境安装

默认安装好了VS2015 和QT

下载QT pdb和QT src压缩包(选择自己的版本,我是5.9.8)

qt下载网址

78c7eb2188522b75fda75f53448bb9aa.png

拷贝自己需要的文件,qt目录中D:\Qt\Qt5.9.8\5.9.8我是这个

4ce9477d0ee508a6e34e1add734602dc.png

并且把源码也拷贝进同一目录,当然其他的目录也行

设置VS选项

工具->选项->调试->符号

5636ab9d940ab04e92fbaa11841721a0.png

项目->xxxx属性->vc++目录(添加源码路径)

0d4f91314d06c5feabcc7f24763ea684.png

8a9b9da986a72c2da7d9565f52d6b5f5.png测试

对着qt的函数或者宏按F12

4239880226d6a08ade25d3ef991d2d9c.png3753a2a8ce4983b7873828f44f3b0693.png

安装查看源码的软件(Source Insight)

这个工具可以很好的分析源码

79d1c8142231c9d79d6cf265b4d7589a.png

8a9b9da986a72c2da7d9565f52d6b5f5.png分析QT信号槽

分析moc生成的文件

案例代码

#include class QtClass : public QObject{    Q_OBJECTpublic:    QtClass(QObject *parent);    ~QtClass();    void Test(){        emit Sig1(5);    }signals:    void Sig1(int nVal);     //void Sig2(bool b);    //void Sig3(bool b);    //void Sig4(bool b, int nVal);    private slots:    void Slot1(int nVal0){        qDebug() << nVal0;    }}

信号函数只有声明,没有实现?

emit Sig1(5);这句代码调用信号,但是我们没有实现信号这个函数呀。我们没有实现,那么是什么能够帮我们实现呢?当然是编译器。

调试信号函数

F11发现是有实现代码的吧

0f5a532ebd13f4277182145a5415c660.png

打开文件所在目录

9716cdf0504d56d6e809e07095eb64fd.pngbbe49d1f7899c7a8d2b173d207579b2a.png

查看moc文件夹,分析编译器都给我们生成了什么

定义了一个结构体

qt_meta_stringdata_QtClass_t

struct qt_meta_stringdata_QtClass_t {     QByteArrayData data[6];     char stringdata0[31];};

后面创建了一个结构体静态变量里面存放一些类、参数、函数名等信息。这个第一个参数应该是ID,字符串的开始位置,字符串size

QT_MOC_LITERAL(0, 0, 7), // "QtClass"

static const qt_meta_stringdata_QtClass_t qt_meta_stringdata_QtClass = {     {QT_MOC_LITERAL(0, 0, 7), // "QtClass" //类名QT_MOC_LITERAL(1, 8, 4), // "Sig1"      //信号名QT_MOC_LITERAL(2, 13, 0), // ""        QT_MOC_LITERAL(3, 14, 4), // "nVal" //参数名QT_MOC_LITERAL(4, 19, 5), // "Slot1" //槽函数名QT_MOC_LITERAL(5, 25, 5) // "nVal0"     //槽参数名     },    "QtClass\0Sig1\0\0nVal\0Slot1\0nVal0"};

qt_meta_data_QtClass : 存储类中函数相关的信息

static const uint qt_meta_data_QtClass[] = {  // content:       7,       // revision  //qt对应版本       0,       // classname        0,    0, // classinfo       2,   14, // methods   //2个函数 context长度14       0,    0, // properties       0,    0, // enums/sets       0,    0, // constructors       0,       // flags       1,       // signalCount //信号数量 // signals: name, argc, parameters, tag, flags       1,    1,   24,    2, 0x06 /* Public */,//name:对应qt_meta_stringdata_QtClass_t结构体的ID,是"Sig1"//argc:是参数个数//parameters:该函数的具体声明在在qt_meta_data_QtClass结构体的偏移 // slots: name, argc, parameters, tag, flags       4,    1,   27,    2, 0x08 /* Private */,//上面的parameters就是指向这里// 返回值   参数1... 这个结构的大小24 // signals: parameters    QMetaType::Void, QMetaType::Int,    3,27 // slots: parameters    QMetaType::Void, QMetaType::Int,    5,       0        // eod};

qt_static_metacall类的信号/槽函数调用的实现地址判断传进来的ID然后调用函数

void QtClass::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, {    if (_c == QMetaObject::InvokeMetaMethod) {        QtClass *_t = static_cast(_o);         Q_UNUSED(_t)         switch (_id) {        case 0: _t->Sig1((*reinterpret_cast< int(*)>(_a[1]))); break;         case 1: _t->Slot1((*reinterpret_cast< int(*)>(_a[1]))); break;         default: ;        }    } else if (_c == QMetaObject::IndexOfMethod) {         int *result = reinterpret_cast<int *>(_a[0]);        {            typedef void (QtClass::*_t)(int );             if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&QtClass::                *result = 0;                 return;            }        }    }}

staticMetaObject : 类信息的总和

红色框是父类地址,蓝色是存储字符串的结构体的地址,黑色是存放信号槽函数信息的结构体,类的信号/槽函数调用的实现地址

66a499f4458871b481c49fda67de394e.png

metaObject:判断静态/动态调用

59c8f584d584168abd69d2c326e0f1d6.png

qt_metacast:返回类名称

b30dc1b3bf8fc07c23a17cac848d6f59.png

+qt_metacall:函数调用

void** _a:数组指针, 每个指针指向一个函数的地址

_c:实现函数的类型

_id : 函数id, 判断是否实现 & 以何种方式实现该函数

cfff8467cfe51b78a5f4040c4a9429d8.png

信号函数的实现

void* _a[]是一个信号对应的槽函数的地址

一个信号可以对应多个槽,所有这里是void* _a[]数组

bd22a6c9176925667b35d34ae6680027.png

Q_OBJECT

从这里看是不是很明显的能看出,这里写了虚函数,然后生成moc文件帮我们实现

* qmake ignore 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 *, Q     QT_WARNING_POP \    struct QPrivateSignal {}; \    QT_ANNOTATE_CLASS(qt_qobject, "")

8a9b9da986a72c2da7d9565f52d6b5f5.png分析connect函数

检查函数

判断参数是否为NULL

84dc73df505e7629cdaf1f74f5e7f6e6.png

给Sender赋值获取名字、对象、参数等

1a6330467654af82ccf7a7d431ef1fcc.png

获取sender的Index,并且判断是否有效

eee3c23c2498eb9e0f1dd0d32b43f9a5.png

接收方信息

08c8c28cd0d3f7feb6e75bf4f3c7c519.png

判断信号槽是否被关联

8e317e4898a074a3a556dc450552f164.png

判断接收方是否有效可以被关联

74b756d3b103312267071b7c46fd923f.png

检查发送者和接收者参数是否一致

571302c08793351a013bb0fce4af32b7.png

执行关联操作函数

4f5ae3c0519cbc1d5ae68b2c7d32ab29.png

进入实现函数

先是强转了sender 和receiver保存在两变量里面

a4583a5705ff54d87462db13355faa23.png

检测版本

a8d681f0b2d35bb30ba611d6b316e7ae.png

估计是为了防止多线程,给了锁

5ed47c73e89ffb12dee6de8f138d1b98.png

生成信号槽的对应关系Connection,并把Connection插入ConnectionList中

6d5ed78030d2c3ae87bda26637f373a1.png

为对应的connect赋值

eef2c279b95a5bad9f48f2c4d0ec2cbb.png

解锁,并且检查是否关联成功

c29c16dd994bb2118313e5924e452b52.png

8a9b9da986a72c2da7d9565f52d6b5f5.png分析activate函数

当我们发Sig1信号时调用的函数

79e4148e2c35c9feee0b6c604fa91bf1.png

红框计算父类的信号

23ce2cf9375cb09390ed382682d9424f.png

前面做了一系列检查,是否还关联着

ff4178e697465b78a8c3110bb0c87837.png

构造一个ConnectListRef的结构体,类似ConnectList引用

8ea2c0b78abf025912014b4046a09d84.png

这里用上面的Index找到关联链表

b4a95c40500b5b47308e026f1a56fb80.png

遍历表找到对应得connect

052c7fdb085a26f0e623889e3a874371.png

调用链表得槽函数

4937cde7a086e361d0e54efa6d5d7365.png

d5a6ff729bf7b545235892af10663beb.pngb8abca310715695bb8d690e277ad5b6e.png

8a9b9da986a72c2da7d9565f52d6b5f5.png大体图

1303a04af1e8293728202651083ebc0c.png

end

0a4156ca5a84adce1d6a90a7e8b8141d.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值