• 【QT】信号与槽


    目录

    概述

    Q_OBJECT 

    自定义信号

    自定义槽

    带参数的信号和槽

    信号与槽断开

    定义槽函数时,使用lambda表达式


    概述

    所谓的信号槽,要解决的问题,就是响应用户的操作,这是QT与其他GUI开发框架比较不同的地方。其他的GUI开发框架,搞的方式都要更简洁一些,例如网页开发中响应用户操作,主要就是挂回调函数,不需要搞一个单独的connect完成上述的信号槽连接。

    Qt信号槽的connect这个机制,主要目的是有:

    • 解耦合,把触发用户操作的控件 和 处理对应用户的操作逻辑 解耦合
    • ”多对多“ 效果,一个信号,可以connect到多个槽函数上,一个槽函数,也可以被多个信号connect

    这里的多对多,可以与mysql中的多对多结合理解

    一个学生,可以选择多门课程来学习

    一门课程,可以被多个同学来选择


    一个信号,可以connect到多个槽函数上

    一个槽函数,可以被多个信号connnect

     可以说 Qt引入信号槽的机制,最本质的目的就是为了能够让信号和槽之间按照“多对多”的方式来进行关联。其他的GUI框架往往也不具备这样的特性。但是在实际开发中很少用到,绝大部分情况下,一对一就够用了

    Q_OBJECT 

     Qt中如果要让某个类能够使用信号槽(可以在类中定义信号和槽函数)则必须要在类最开始的地方,写下Q_OBJECT宏

    自定义信号

    Qt中也允许自定义信号,自定义信号比较少见,实际开发中很少需要自定义信号,信号对应到用户的某个操作,在GUI,用户能够进行哪些操作,是可以穷举的,Qt内置的信号,基本上已经覆盖到了上述所有可能的用户操作。

    1. 信号是一类非常特殊的函数,程序员只要写出函数声明,并且告诉Qt,这是一个”信号即可“,这个函数的定义,是Qt在编译过程中,自动生成的,程序员无法干预。
    2. 信号在Qt中是特殊的机制,Qt生成的信号函数的实现,要配合Qt框架做很多既定的操作。
    3. 作为信号函数,这个函数的返回值,必须是void,有没有参数都可以,甚至也可以支持重载

    代码实例:

    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3. #include
    4. QT_BEGIN_NAMESPACE
    5. namespace Ui { class Widget; }
    6. QT_END_NAMESPACE
    7. class Widget : public QWidget
    8. {
    9. Q_OBJECT
    10. public:
    11. Widget(QWidget *parent = nullptr);
    12. ~Widget();
    13. signals:
    14. void mySignal();
    15. public:
    16. void handleMySignal();
    17. private:
    18. Ui::Widget *ui;
    19. };
    20. #endif // WIDGET_H
    1. #include "widget.h"
    2. #include "ui_widget.h"
    3. Widget::Widget(QWidget *parent)
    4. : QWidget(parent)
    5. , ui(new Ui::Widget)
    6. {
    7. ui->setupUi(this);
    8. //这里只是建立链接,并未发出信号
    9. connect(this,&Widget::mySignal,this,&Widget::handleMySignal);
    10. //发出自定义的信号
    11. emit mySignal();
    12. }
    13. Widget::~Widget()
    14. {
    15. delete ui;
    16. }
    17. void Widget::handleMySignal()
    18. {
    19. this->setWindowTitle("123");
    20. }

    自定义槽

    自定义槽函数是非常关键的,开发中大部分情况都是需要自定义槽函数的,槽函数就是用户触发某个操作后,要进行的业务逻辑

    所谓的slot就是一个普通的成员函数,自定义一个槽函数,操作过程和自定义一个普通的成员函数一样。

    另一种自定义槽函数的方式是 在图形化界面中右键 转到槽

    随后跳转的窗口就是 QPushButton给我们提供的所有的信号(还包含了QPushButton 父类的信号)

    在Qt中,除了通过connect来连接信号槽之外,还可以通过函数名字的方式来自动连接

    如果我们通过图形化界面创建控件,还是推荐使用这种快速的方式来连接信号槽

    如果我们是通过代码的方式来创建控件,还是得手动connect(因为我们的代码中没有调用connectSlotByName)

    带参数的信号和槽

    当信号带有参数的时候,槽的参数必须和信号的参数一致,此时发射信号的时候,就可以给信号函数传递实参,与之对应的这个参数就会传递到对应的槽函数中。

    这里的参数一致主要是要求类型,个数如果不一致也可以,不一致的时候,要求信号的参数的个数必须要比槽的参数个数要更多。

    如果我们严格要求参数个数一致,就意味着信号绑定到槽的要求就变高了,换而言之,当下这样的规则就允许信号和槽之间绑定更灵活了,更多的信号可以绑定到这个槽函数上了

    信号与槽断开

    使用 disconnect 来断开信号槽的连接,disconnect使用的方式和connect是非常类似的。 

    disconnect用的比较少,大部分的情况下,把信号和槽连上之后,就不必管了,主动断开往往是把信号重新绑定到另一个槽函数上。

    定义槽函数时,使用lambda表达式

    代码示例:

    1. QPushButton* button = new QPushButton(this);
    2. button->setText("按钮");
    3. button->move(200,200);
    4. connect(button,&QPushButton::clicked,this,[](){
    5. qDebug()<<"lambda被执行了";
    6. })

     lambda表达式是一个回调函数,这个函数是无法直接获取到上层作用域中的变量,lambda为了解决这个问题,引入了“变量捕获”语法,通过变量捕获,获取到外层作用域中的变量

    1. connect(button,&QPushButton::clicked,this,[button,this](){
    2. qDebug()<<"lambda被执行了";
    3. button->move(300,300);
    4. this->move(100,100);
    5. });

    如果 当前lambda里面想使用更多的外层变量,我们可以写作 [=] ,这个写法的含义就是把上层作用域中的所有变量名都给捕获进来。

    lambda除了可以按照 值的方式来捕获变量 [=] 还可以按照引用的方式来捕获 [&](Qt中很少这么写)捕获到的变量一般就是各种控件的指针,指针变量按照值传递或者引用来传递,都无所谓。

    需要注意的是 lambda语法是C++11中引入的,对于Qt 5及其更高版本,默认就是按照C++ 11来编译的,如果使用Qt 4 或者更老的版本,就需要手动在 .pro 文件中加上C++11 的编译选项,如下:

    CONFIG += c++11 

  • 相关阅读:
    gptp报文完成时间同步原理
    Web 前端 之 Vue webpack 环境的搭建及工程创建简单整理
    C++【STL】【string类的模拟实现】【string类的深浅拷贝】
    Jmeter(115)——在jmeter中写入xls文件的基本方法
    c语言进阶篇:自定义类型--结构体
    分布式链路追踪(一)SkyWalking(1)介绍与安装
    探索云原生时代:技术驱动的业务架构革新
    Vue3统一导出局部组件和全局组件
    MySQL 索引优化及失效场景
    【设计模式实战】状态模式:原理篇
  • 原文地址:https://blog.csdn.net/lzb_kkk/article/details/139573919