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 #include 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:信号与槽的基础部分就到这里了,谢谢观看!!!

相关推荐
我叫小白菜14 分钟前
【Java_EE】单例模式、阻塞队列、线程池、定时器
java·开发语言
天水幼麟20 分钟前
动手学深度学习-学习笔记(总)
笔记·深度学习·学习
狐凄21 分钟前
Python实例题:基于 Python 的简单聊天机器人
开发语言·python
weixin_446122461 小时前
JAVA内存区域划分
java·开发语言·redis
悦悦子a啊1 小时前
Python之--基本知识
开发语言·前端·python
QuantumStack2 小时前
【C++ 真题】P1104 生日
开发语言·c++·算法
whoarethenext2 小时前
使用 C++/OpenCV 和 MFCC 构建双重认证智能门禁系统
开发语言·c++·opencv·mfcc
天水幼麟3 小时前
动手学深度学习-学习笔记【二】(基础知识)
笔记·深度学习·学习
沧海一笑-dj3 小时前
【51单片机】51单片机学习笔记-课程简介
笔记·学习·51单片机·江科大·江科大学习笔记·江科大单片机·江科大51单片机
代码的奴隶(艾伦·耶格尔)3 小时前
后端快捷代码
java·开发语言