• 【QT】信号和槽机制


    💦信号槽

    信号槽是Qt框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的。类似广播。如果有对象对这个信号感兴趣。它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

    💦系统自带的信号和槽

    connect(sender,signal,receiver,slot);
    参数解释:
    sender:发出信号的对象;
    signal:发送对象发出的信号
    receiver:接收信号的对象
    slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

    //widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    #include 
    #include 
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        QPushButton *p;
        ~Widget();
    };
    
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    //widget.cpp
    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        p = new QPushButton("关闭",this);
        //设置连接,点击按钮产生信号,会调用窗口的close函数
        connect(p,&QPushButton::clicked,this,&QWidget::close);
    }
    
    Widget::~Widget()
    {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 点击运行
      在这里插入图片描述

    💦自定义信号与槽

    💦自定义槽函数

    //widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    #include 
    #include 
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        QPushButton *p;
        ~Widget();
    //声明槽函数
    public slots:
        void print();
    };
    
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    //widget.cpp
    #include "widget.h"
    #include 
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        p = new QPushButton("按下",this);
        //设置连接,点击按钮产生信号,会调用窗口的自定义的函数
        //如果信号没有参数,槽函数也不能有参数,即槽函数参数<=信号参数
        connect(p,&QPushButton::pressed,this,&Widget::print);
    }
    
    void Widget::print()
    {
        qDebug()<<"你点击了按钮";
    }
    
    Widget::~Widget()
    {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    💦自定义信号

    💦功能需求

    在这里插入图片描述

    💦实现功能

    //sonwidget.h
    #ifndef SONWIDGET_H
    #define SONWIDGET_H
    
    #include 
    #include 
    class SonWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit SonWidget(QWidget *parent = nullptr);
        QPushButton *button2;
    signals:
        void show_signal();
    public slots:
        void emitMySignal();
    };
    
    #endif // SONWIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    //sonwidget.cpp
    #include "sonwidget.h"
    
    SonWidget::SonWidget(QWidget *parent) : QWidget(parent)
    {
        this->setWindowTitle("子窗口");
        this->resize(300,300);
        button2 = new QPushButton("隐藏子窗口,显示父窗口",this);
        connect(button2,&QPushButton::clicked,this,&SonWidget::emitMySignal);
    }
    
    void SonWidget::emitMySignal()
    {
        emit show_signal();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    //widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    #include "sonwidget.h"
    #include 
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
        SonWidget *sonwidget;
        QPushButton *button1;
    public slots:
        void buttonHide();
        void buttonShow();
    };
    
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //widget.cpp
    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        this->setWindowTitle("父窗口");
        this->resize(400,400);
        this->sonwidget = new SonWidget;
        sonwidget->show();
        button1 = new QPushButton("隐藏父窗口,显示子窗口",this);
        connect(button1,&QPushButton::clicked,this,&Widget::buttonHide);
        connect(sonwidget,&SonWidget::show_signal,this,&Widget::buttonShow);
    }
    void Widget::buttonHide()
    {
        this->hide();
        this->sonwidget->show();
    }
    void Widget::buttonShow()
    {
        this->show();
        this->sonwidget->hide();
    }
    Widget::~Widget()
    {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 实现效果
      在这里插入图片描述

    💦自定义信号槽注意事项

    • 发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda表达式等无需接收者的时候除外);
    • 信号和槽函数返回值是void
    • 信号只需要声明,不需要实现
    • 槽函数需要声明也需要实现
    • 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
    • 使用emit在恰当的位置发送信号:
    • 使用connect()函数连接信号和槽。
    • 任何成员函数、static函数、全局函数和Lambda表达式都可以作为槽函数
    • 信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
    • 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)

    💦信号槽的拓展

    • 一个信号可以和多个槽相连
      如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
    • 多个信号可以连接到一个槽
      只要任意一个信号发出,这个槽就会被调用。
    • 一个信号可以连接到另外的一个信号
      当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
    • 槽可以被取消链接
      这种情况并不经常出现,因为当一个对象delete之后,Ot自动取消所有连接到这个对象上面的
      槽。
    • 信号槽可以断开
      利用disconnect关键字是可以断开信号槽的
    • 使用Lambda 表达式
      在使用Qt5的时候,能够支持Qt5的编译器都是支持Lambda表达式的。在连接信号和槽的时候,槽函数可以使用Lambda表达式的方式进行处理。

    💦Lambda表达式

    C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:

    [capture](parameters) mutable->return-type
    {
    statement
    }
    
    • 1
    • 2
    • 3
    • 4

    [函数对象参数](操作符重载函数参数)mutable->返回值{函数体}

    1. 函数对象参数:
      [],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动 生成的函数对象类的构造函数的。函数对鱼参数只能使用那此到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
      。没有使用任何函数对象参数。
      =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
      &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
      this。函数体内可以使用Lambda所在类中的成员变量。
      a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mtable修饰符。
      &a。将a按引用进行传递。
      a,&b。将a按值进行传递,b按引用进行传递。
      =,&a.&b。除a和b按引用进行传递外,其他参数都按值进行传递。
      &,a,b。除a和b按值进行传递外,其他参数都按引用进行传递。
    2. 操作符重载函数参数:
      标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a.b))和按引用(如:(&a.&b))两种方式进行传递。

    💦Qt4版本的信号槽写法

    connect(zt,SIGNAL(hungry(QString)),st,SLOT(treat(QString)));
    这里使用了 SIGNAL和 SLOT 这两个宏,将两个函数名转换成了字符串。注意到connect()函数的signal和slot都是接受字符串,一旦出现连接不成功的情况,Qt4是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。
    Qt5 在语法上完全兼容 Qt4,而反之是不可以的。

  • 相关阅读:
    整型提升——(巩固提高——字符截取oneNote笔记详解)
    零时科技 | Nomad 跨链桥被盗1.8亿美元事件分析
    React——react 的基本使用
    QEMU显示虚拟化的几种选项
    AI变现之Gpts搞流量+赚钱
    web前端安全性——XSS跨站脚本攻击
    55跳跃游戏
    Flutter 实现用户偏好标签设置
    《数据结构与算法》线性结构复习题
    【Linux】 - Linux中的文件操作
  • 原文地址:https://blog.csdn.net/qq_36477513/article/details/126275351