Qt的学习(三)

1.信号与槽

1.1 信号与槽的定义

Qt中,谈到信号,也是涉及到三个要素

信号源:由哪个控件发出的信号

信号的类型:用户进行不同的操作,就可能触发不同的信号(点击按钮,触发点击信号;在输入框中移动光标,触发移动光标的信号;勾选一个复选框;选择一个下拉框 都会触发出不同的信号)。咱们写的GUI程序,就是要和用户进行交互,这个过程中就需要关注,用户当前的操作具体是个什么样的操作

信号的处理方式:槽(slot) =>函数,Qt中可以使用connect这样的函数,把一个信号和一个槽关联起来后续只要信号触发了,Qt就会自动的执行槽函数

所谓的"槽函数"本质上也是一种"回调函数"(callback)。

在Qt中,一般先关联好信号和槽,然后再触发这个信号,顺序不能颠倒,否则信号就不知道如何被处理了。

connect是QObject提供的静态的成员函数,Qt中提供的这些类,本身是存在一定的继承关系的。QObject就是其他Qt内置类的默认父类。

1.2 connect的使用方式

所谓的信号也是Qt中的对象,内部提供的一些成员函数。

代码如下:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

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,&Widget::close);
}

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

1.3 自定义槽

所谓的自定义一个槽函数,和定义一个普通的成员函数没什么区别。

f1:纯代码方式

cpp 复制代码
class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;
};
cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* button = new QPushButton(this);
    button->setText("按钮");
    button->move(100,100);

    connect(button,&QPushButton::clicked,this,&Widget::handleClicked);
}

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

void Widget::handleClicked()
{
    //按下按钮就修改一下窗口的标题
    this->setWindowTitle("按钮已经按下");
}

f2:图形化界面操作

槽函数,就是用户厨房某个操作之后要进行的业务逻辑。

信号就对应到用户的某个操作。

1.4 自定义信号

1、信号,则是一类非常特殊的函数,我们只要写出函数声明,并且告诉Qt,这是一个"信号"即可,至于函数的定义,是Qt在编译过程中,自动生成的.(自动生成的过程,程序员无法干预)。信号在Qt中是特殊的机制.Qt生成的信号是函数的实现,要配合Qt框架做很多既定的操作

2 、作为信号函数,这个函数的返回值,必须是void。该函数有没有参数都可以,也可以支持重载

signals:是Qt自己扩展出来的关键字,qmake的时候,调用一些代码的分析/生成工具,当扫描到类中包含signals这个关键字的时候,就会自动的把下面的函数声明认为是信号,并且给这些信号函数自动的生成函数定义。

信号和槽也可以带参数

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

信号函数的参数个数,超过了槽函数的参数个数,此时,都是可以正常使用的。

信号函数的参数个数,少于槽函数的参数个数,此时代码无法编译通过 。

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

槽函数按照参数顺序,拿到信号的前n个参数。

1.5 关于信号和槽的其他知识点

1、使用disconnect来断开信号槽的连接

disconnect使用的方式和connect是非常类似的,disconnect用的比较少的。大部分的情况下,把

信号和槽连上了之后,就不必管了。主动断开往往是把信号重新绑定到另一个槽函数上。

cpp 复制代码
#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();
    void handleClick();
    void handleClick2();

private slots:
    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);
}

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

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

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


void Widget::on_pushButton_2_clicked()
{
    //1、先断开pushbutton原来的信号槽
    disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);
    //2、重新绑定信号槽
    connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick2);
    //如果1步骤注销,也就是没有进行断开连接操作,点击按钮,就会发现信号连接了两个槽函数,即实现了一对多的效果

}

2、定义槽函数的时候,也可以使用lambda表达式,lambda表达式其本质就是一个匿名函数,主要运用在回调函数中,并且是一次性使用。

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

=是把上层作用域中的所有变量捕获进来。

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表达式被执行了!";
        //lambda表达式是一个回调函数
        //它无法直接获取上层作用域中的变量
        button->move(300,300);
        this->move(200,200);
    });
}

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

上述this指的是widget这个对象,该对象实在main函数中创建成的,即在main函数结束时销毁,main函数结束通常说明进程结束了。所以可以理解为只要进程不结束,widget和this就可以一直使用。

ps:信号与槽的基础部分就到这里了,谢谢观看!!!

相关推荐
IT猿手4 小时前
多目标优化算法:多目标蛇优化算法(Multiple Objective Snake Optimizer,MOSO)(提供MATLAB代码)
开发语言·算法·matlab·动态路径规划·光伏模型参数估计
朔北之忘 Clancy4 小时前
2026 年 3 月青少年软编等考 C/C++ 一级真题解析
c语言·开发语言·c++·青少年编程·题解·考级
小成202303202654 小时前
C++~01面向对象基础
开发语言·c++
会编程的土豆5 小时前
Go 方法接收者超清晰笔记(类型名 vs 变量名)
开发语言·笔记·golang
峥嵘life5 小时前
Android 蓝牙设备连接广播详解-2026
android·python·学习
楼田莉子5 小时前
Docker学习:Docker介绍及其架构介绍
运维·后端·学习·docker·容器·架构
YY&DS5 小时前
Qt 嵌入 CEF 在 Linux 下必须设置 `QT_XCB_GL_INTEGRATION=xcb_egl才能加载网页
linux·开发语言·qt
csdn_aspnet5 小时前
javascript 算法 LeetCode 编号 70 - 爬楼梯
开发语言·javascript·算法·leetcode·ecmascript
星夜夏空995 小时前
FreeRTOS学习(7)——任务列表
java·前端·学习
不羁的木木5 小时前
Form Kit(卡片开发服务)学习笔记01-核心概念与架构设计
笔记·学习·harmonyos