004 信号与槽_下

前言

本文将会向你介绍信号与槽中:自定义信号、disconnect、lambda表达式定义槽函数等相关概念

自定义信号

在开发中,很少会使用到自定义信号,在Qt内置的信号,基本上能够覆盖用户的所有操作,足以应付大部分的开发场景

包含Qt5在内以及更高的版本中,槽函数与普通的成员函数已经没有区别,但是信号则是一类特殊函数
1、只需要写出函数声明,并且告诉Qt这是一个”信号“即可,这个函数的定义,是Qt在编译过程中,自动生成的(自动生成的过程,程序员无法进行干预)。因为信号在Qt中是特殊的机制,Qt生成的信号函数的实现,要配合Qt框架做很多既定的操作
2、作为信号函数,这个函数的返回值,必须为void,有没有参数都可以,也可以支持重载

Widget.h文件所需要做的修改如下

在这里插入图片描述
一个clicked信号对应了两个槽函数,这样也是符合规定的

private slots:
    //点击信号clicked对应的槽函数
    void on_pushButton_clicked();
    //点击信号clicked对应的槽函数
    void on_pushButton_2_clicked();

在Qt中以下情况都是可以的
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Widget.cpp文件所需要做的修改如下

在这里插入图片描述

对重点代码进行解释说明:

将自定义信号 mySignal 连接到槽函数 handleMySignal,注意connect只是将信号与槽建立了连接,不代表信号发出来了,因此我们还需要进行发送信号。
上一篇文章中我们自定义槽函数,并通过clicked信号触发事件,点击按钮时就调用对应的槽函数(这里不用手动发送信号的原因是:Qt内置的信号(如clicked),不需要手动通过代码来触发,发射信号的代码已经内置到Qt框)

connect(this, &Widget::mySignal, this, &Widget::handleMySignal);

与信号对应的槽函数

void Widget::handleMySignal(const QString& text)
{
    this->setWindowTitle(text);
}

点击按钮触发clicked信号所对应的槽函数:功能为发送信号

void Widget::on_pushButton_clicked()
{
    emit mySignal("把标题设置为文本一", "");    
}

void Widget::on_pushButton_2_clicked()
{
    emit mySignal("把标题设置为文本二", "");
}

大致流程如下:
connect将自定义信号 mySignal 连接到槽函数 handleMySignal
点击按钮 =>触发clicked信号 => 执行对应的槽函数:emit mySignal() 槽函数中发送信号 => 执行自定义信号的槽函数handleMySignal()

带参数的信号槽

传参可以起到复用代码的效果,可以通过函数-参数来复用代码

信号函数以及与其对应的槽函数声明:
在这里插入图片描述
此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中
在这里插入图片描述
信号函数的参数个数即使超过了槽函数的参数个数,也是被允许的,但是槽的参数个数不能多于信号参数个数,实际开发中最好还是保持参数个数也能匹配⼀致.

为什么允许信号参数的个数可以大于槽函数的参数个数呢?

因为一个信号,可能会绑定多个槽函数,信号可以向多个槽发出通知,如果严格要求参数个数一致,就意味着信号绑定槽的要求变高了。如果信号的参数个数多于槽的参数个数,Qt将只传递与槽函数参数相对应的信号参数。至少需要确保槽函数的每个参数都是有值的,所以信号给槽传参的个数,可以有多,但是绝不能少

信号与槽的断开

使⽤ disconnect 即可完成断开.
disconnect 的⽤法和 connect 基本⼀致.

以下我们主要实现通过disconnect达到切换槽函数的作用
widget.h中所需要的修改

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handleClick();
    void handleClick2();

private slots:
    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
    QPushButton *pushButton;
};
#endif // WIDGET_H


widget.cpp中所需要的修改

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    pushButton = new QPushButton(this);
    pushButton->setText("按钮");
    pushButton->move(100, 100); //将按钮的位置设定为 (100, 100),相对于其父窗口的坐标系
    connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handleClick()
{
    this->setWindowTitle("修改窗口的标题");
    qDebug() << "handleClick";
}

void Widget::handleClick2()
{
    this->setWindowTitle("修改窗口的标题2");
    qDebug() << "handleClick2";
}

void Widget::on_pushButton_2_clicked()
{
    disconnect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
    connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}


切换槽函数d

void Widget::on_pushButton_2_clicked()
{
    disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}

(注释1): 槽函数:disconnect:断开名为按钮的控件的clicked信号与其槽函数一的连接。
connect:连接名为按钮的控件与其槽函数二

void Widget::on_pushButton_2_clicked()
{
    disconnect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
    connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}

槽函数一:

void Widget::handleClick()
{
    this->setWindowTitle("修改窗口的标题");
    qDebug() << "handleClick";
}

槽函数二:

void Widget::handleClick2()
{
    this->setWindowTitle("修改窗口的标题2");
    qDebug() << "handleClick2";
}

如果点击名为切换槽函数的控件,再点击名为按钮的控件就会调用槽函数二,否则二调用槽函数一
在这里插入图片描述

使用lambda表达式定义槽函数

Qt5 在 Qt4 的基础上提⾼了信号与槽的灵活性,允许使⽤任意函数作为槽函数。
但如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式来达到这个⽬的。
Lambda表达式 是 C++11 增加的特性。C++11 中的 Lambda表达式 ⽤于定义并创建匿名的函数对
象,以简化编程⼯作。

Lambda表达式 的语法格式如下:
[ capture ] ( params ) opt -> ret {
Function body;
};
在这里插入图片描述

widget.h所需要做的修改

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp所需要做的修改

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton* button = new QPushButton(this);
    button->setText("按钮");
    button->move(200, 200);
    connect(button, &QPushButton::clicked, this, [=](){
        qDebug() << "lambda 被执行了!";
        button->move(300, 300);
    });
}

Widget::~Widget()
{
    delete ui;
}


由于lambda表达式是一个回调函数,是无法直接获取到上层作用域中的变量的,lambda为了解决这个问题,引入了变量捕获的语法,通过变量捕获,来获取到外层作用域中的变量
如下:无法获取到外部的变量
在这里插入图片描述

符号说明
[a]在函数体内部使⽤值传递的⽅式访问a变量
[&b]在函数体内部使⽤引⽤传递的⽅式访问b变量
[=]函数外的所有局部变量都通过值传递的⽅式使⽤, 函数体内使⽤的是副本
[&]以引⽤的⽅式使⽤Lambda表达式外部的所有变量
[=, &foo]foo使⽤引⽤⽅式, 其余是值传递的⽅式
[&, foo]foo使⽤值传递⽅式,其余引⽤传递
[this]在函数内部可以使⽤类的成员函数和成员变量,= 和 & 形式也都会默认引⼊
这里采用[=] 含义就是把上层作用域中的所有变量名按照值得方式都捕获进来,如果使用[&]引用的方式捕获,捕获到的变量就是各种控件的指针,但是还得关注这个引用的变量本身的生命周期

小结

今天是1024,祝各位平安顺遂哈~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fan_558

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

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

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

打赏作者

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

抵扣说明:

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

余额充值