【Qt专栏】Qt 中信号与槽的概念和实现机制

目录

一,信号和槽概念

1.元对象系统 

2.信号和槽

3.底层实现机制

二,什么是观察者设计模式

三,观察者设计模式的编程套路

四,纯 C++ 实现信号与槽机制

1.槽函数模板类

2.信号模板类

3.connect 宏

4.测试代码

5.运行结果

6.解决 VS Code 终端乱码问题 


一,信号和槽概念

1.元对象系统 

Qt中信号和槽不是 C++ 标准代码,在使用这一核心机制时就需要使用Qt的 MOC(元对象编译器) 进行预处理(MOC其实是一个预处理器),在由标准 C++编译器 进行重新编译。

元对象系统基于以下三点组成:

  1. QObject 类是所有元对象系统的类的。
  2. 在一个类的private部分声明 Q_OBJECT 宏,使得类可以使用元对象的特性,如信号与槽。
  3. MOC 为每个的子类提供必要的代码来实现元对象系统的属性。

2.信号和槽

信号和槽是对象间进行通信的机制,也必须要由Qt的元对象系统支持才能实现。

信号和槽之间的关系:

  1. 信号的参数的类型必须与槽函数的参数的类型相对应。
  2. 信号的参数个数大于等于槽函数的参数的个数。
  3. 信号和槽函数之间的 connect 关系是多对多,信号也可以 connect 到另一个信号上。

3.底层实现机制

  • 观察者设计模式

二,什么是观察者设计模式

  • 观察者模式 是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。
  • 观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用
  • 观察者模式(Observer)完美的将观察者和被观察的对象分离开,观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

三,观察者设计模式的编程套路

  1. 设计两者类,一个为观察者类(触发槽函数),一个为被观察者类(信号发布)
  2. 观察者类中,定义一个对某个事件感兴趣的处理函数,也就是槽函数。
  3. 被观察者类中,定义一个数据结构,用来保存观察者对哪一个事件感兴趣,可以使用vector建立对应关系。
  4. 被观察者类中,实现两个接口函数:
    1. (接口一)添加观察者与其感兴趣的事件加入容器中。
    2. (接口二)通知事件函数执行逻辑处理,首先遍历容器中有没有感兴趣的事件,如果有,则代表一系列的观察者对这个事件感兴趣,那么再次遍历观察者列表,让每一个观察者执行相应的槽函数。

四,纯 C++ 实现信号与槽机制

1.槽函数模板类

template <typename TParam>
class SlotBase
{
public:
    virtual void slotFunction(TParam) = 0;      //占位参数:不用写参数名称
    virtual ~SlotBase() = default;      //纯析构函数
};

template <class TRecver,typename TParam>
class Slot:public SlotBase<TParam>
{
private:
    TRecver* m_pSlotObj;     //定义一个接收者(serder)的指针,在构造中对其初始化。
    void (TRecver::*m_slotFunc)(TParam);   //定义一个接收者类中的成员函数指针,在构造中对其初始化。
public:
    Slot(TRecver* pObj,void(TRecver::*recverFunc)(TParam))
    {
        this->m_pSlotObj = pObj;    //使用类外的接收者类的对象指针进行初始化。
        this->m_slotFunc = recverFunc;    //使用类外的接收者类中的成员函数指针进行初始化。
    }
    void slotFunction(TParam param)override
    {
        (m_pSlotObj->*m_slotFunc)(param);    //成员对象指针调用类内的成员函数
    }
};

2.信号模板类

template <typename TParam>
class Signal
{
private:
    vector<SlotBase<TParam>*> signal_vector;    //用于触发槽函数
public:
    template<class TRecver>
    void addSlot(TRecver* pSlotObj,void (TRecver::*slotFunc)(TParam))
    {
        auto slotObj = new Slot<TRecver,TParam>(pSlotObj,slotFunc);
        signal_vector.push_back(slotObj);
    }

    void operator()(TParam param)
    {
        for(auto p : signal_vector){
            p->slotFunction(param);
        }
    }
};

3.connect 宏

#define connect(sender,signal,recver,slotFunc) (sender)->signal.addSlot(recver,slotFunc)

4.测试代码

class Recver1
{
public:
    void func1(int param)
    {
        cout << "这是 Recver1 中的方法,参数为:" << param << endl;
    }
};

class Recver2
{
public:
    void func2(int param)
    {
        cout << "这是 Recver2 中的方法,参数为:" << param << endl;
    }
};

class Sender
{
public:
    Signal<int> valueChanged;
public:
    void testSignal(int value){
        valueChanged(value);
    }
};
//以上为三个毫无相关的 Demo 类

int main()
{
    Recver1* r1 = new Recver1;
    Recver2* r2 = new Recver2;

    Sender* sd = new Sender;

    connect(sd,valueChanged,r1,&Recver1::func1);
    connect(sd,valueChanged,r2,&Recver2::func2);

    sd->testSignal(1314520);
    return 0;
}

5.运行结果

6.解决 VS Code 终端乱码问题 

1.在Windows系统下,VS Code 使用的是Windows的终端,也就是嵌入进去的,而Windows自带的终端编码格式是 GBK(右击终端选择属性,然后按如下图操作可查看 cmd 的编码格式),而 VS Code 默认使用的编码格式是 UTF-8,所以会出现乱码现象。

2.单文件修改方法:按如下图操作,在编码格式项选择 GB2312 或者 GBK,但这只会修改当前源文件的编码格式,在新建一个源文件使用的还是 VS Code 默认的 UTF-8 编码格式,所以唯有源头活水来。

3.多文件修改方法:也就是直接修改 VS Code 的默认编码格式,就不用担心每新建一个源文件就按步骤2修改一次编码格式了,如下图操作,选择 GB2312 或者 GBK 即可。

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Qt,可以使用Qt提供的Json类来组织和解析数据。Qt从版本5.0开始提供了对Json的支持。主要有四个与Json相关的类常用:QJsonDocument、QJsonArray、QJsonObject和QJsonValue。 QJsonDocument类封装了一个完整的JSON文档,可以从基于文本的UTF-8编码的表示以及Qt的二进制格式读取和写入该文档。 QJsonArray表示JSON数组,是一个值的列表。可以通过插入和删除QJsonValue来操作该列表。 QJsonObject表示JSON对象,是键值对的列表,其键是唯一的字符串,值由QJsonValue表示。 QJsonValue类封装了JSON支持的数据类型。 QJsonParseError类用于报告JSON解析过程的错误。 对于Json的使用,可以参考以上提到的类的文档和相关函数进行操作,根据具体的需求进行数据的组织和解析。Json格式的数据在Qt可以方便地进行处理,并且由于Json的数据格式与语言无关,因此在Qt的Json使用具有广泛的应用场景。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【QTQt Json 的操作](https://blog.csdn.net/qq_43331089/article/details/124582761)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [【Qt专栏QtJson的使用教程](https://blog.csdn.net/weixin_43729127/article/details/127522889)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉伊卜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值