当前位置: 首页 > article >正文

Qt信号和槽【2】

文章目录

    • 1. 带参数的信号槽
    • 2. 信号和槽存在的意义
    • 3. 信号和槽断开连接
    • 4. lambda表达式定义槽函数

1. 带参数的信号槽

Qt的信号和槽也支持带参数。

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

image-20240904205208731

参数必须一致,这里的一致主要是类型一致

个数不一致也可以,不一致的时候,要求信号的参数个数多余槽函数的参数个数,这是因为一个槽可能会绑定多个信号,如果严格要求就意味着绑定到槽的要求变高了,所以适当放宽规则,更多的信号就能绑定到槽函数上。

image-20240904205939375

带参数就可以起到复用代码的效果

image-20240904211028418

在写类的声明的时候,加上了一个Q_OBJECT这个宏

image-20240904211357465

在Qt中,如果要某个类,能够使用信号和槽,就必须在类最开始的地方,写下这个宏,这是Qt的硬性规定

这个宏能展开成很多额外的代码

2. 信号和槽存在的意义

所谓的信号槽,最终还是要解决问题,即响应用户的操作

Qt属于GUI开发框架当中,稍微复杂一定的了,其他的可能更简洁一点。

Qt信号槽,较为理想主义:

  1. 信号和槽解耦,把触发用户操作的控件和处理对应用户的操作逻辑解耦
  2. 可以实现“多对多”,一个信号可以connect到多个槽函数,一个槽函数也可以被多个信号connect

最本质的初心就是让信号和槽之间按照“多对多”的方式进行关联。

不过在实际开发过程当中,很少用到,所以现在新出的一些图形化开发框架,就没有再支持这种多对多了

3. 信号和槽断开连接

可以使用disconnect来断开信号槽的连接,使用方式和connect类似

disconncet用的比较少,大部分情况下,把信号和槽连接上,就不必管了

主动断开往往是把信号重新绑定到另一个槽函数上

#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick1);
}

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

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


void Widget::on_pushButton_2_clicked()
{
    //断开 pushbutton 原来的信号槽
    disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick1);
    //重新绑定
    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}

GIF 2024-9-4 22-13-26

如果没有disconncet,那么一个信号就会绑定多个槽函数

GIF 2024-9-4 22-16-28

4. lambda表达式定义槽函数

不了解lambda表达式的,可以先看此篇文章:C++11——lambda表达式

定义槽函数的时候,可以使用lambda表达式

#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,300);

    connect(button, &QPushButton::clicked, this, [](){
        qDebug() << "lambda 执行";
    });

}

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

image-20240904222857414

这就是lambda表达式的基本使用方法,但是如果想执行某种操作,例如移动按钮:

image-20240904223044074

这里报错找不到定义,这其实是因为lambda表达式是一个回调函数,无法直接获取到上层作用域的变量

lambda为了解决上述问题,可以通过列表捕获,获取到外层作用域中的变量

#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,300);

    connect(button, &QPushButton::clicked, this, [button,this](){
        qDebug() << "lambda 执行";
        button->move(300,300);
        this->move(1000,800);
    });

}

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

image-20240904223822524

如果想要使用很多外层变量,可以直接写成[=],这样就能捕捉所有上层作用域变量

这里要注意的是,要确保捕获的lambda内部变量是有意义的,因为lambda本质是回调函数,用户什么时候点击,并不确定。所有要确保无论用户什么时候点击,捕获的变量都能正确使用,例如这个button是在堆上创建的,生命周期随整个窗口,可以随时使用

QPushButton *button = new QPushButton(this);

如果开发的时候,槽函数比较简单,而且是一次性,就可以写成这种lambda表达式。

lambda表达式是C++11引入的,对于Qt5及更高的版本,默认就是按照C++11来编译的

如果是Qt4或者更老的版本,就需要手动在pro文件加上C++11的编译选项

image-20240904224822078


http://www.kler.cn/a/298128.html

相关文章:

  • 动态规划算法之背包问题详细解读(附带Java代码解读)
  • SPDK 部署NVMe over TCP
  • 将BAT脚本设置为Windows开机自启动
  • LLM - 理解 多模态大语言模型 (MLLM) 的发展与相关技术 (一)
  • 如何用Stable diffusion三步搞定场景定制化?这些经验你一定要知道!AI绘图SD商业化实战教程!
  • 基于Neo4j知识图谱的构建及可视化
  • 企业架构对现代企业的价值:改进流程、提高效率和更好的决策
  • FALCON:打破界限,粗粒度标签的无监督细粒度类别推断,已开源| ICML‘24
  • 【较真儿】事务特性及场景演化:
  • DynamiCrafter模型构建教程
  • weititer0000
  • Spring boot 项目作为客户端调用 服务端websocket
  • 传输大咖41 | 如何解决汽车行业大文件传输难题?
  • Qt/C++ Mysql数据库用户登录分配软件(源码分享)
  • 关于.NET在中国为什么工资低的分析
  • 【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)
  • 网络编程day02(字节序、TCP编程)
  • 汽车电子行业知识:关于域控制器
  • 目标检测的损失函数
  • vscode docker debug python