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

Qt信号和槽-->day04

Qt信号和槽

  • 标准的信号和槽函数
    • Qt中的槽函数
    • Qt中的信号
  • connect
    • 案例
  • 自定义信号和槽
    • 案例分析
  • 信号槽的拓展
    • 信号连接信号案例
  • 信号槽的两种连接方式
    • Qt5中的处理方式
    • Qt4中的处理方式
    • Qt5处理信号槽重载问题
      • 案例
    • lambda表达式
      • 简单案例
      • Qt中的应用
  • 补充知识点

标准的信号和槽函数

QWidget标准的信号和槽函数
在这里插入图片描述
此外信号和槽函数是可以被继承的
在这里插入图片描述
可以看到QPushButton是有标准的槽函数,但是没有看到信号。
实际上QPushButton是继承了它的父类的信号
在这里插入图片描述

Qt中的槽函数

Qt中的槽函数可以是类的成员函数、全局函数、静态函数、Lambda表达式(匿名函数)

Qt中的信号

信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字

connect

connect(信号发生者,信号,信号接受者,接受者的处理动作);

connect只是做了一个信号注册,具体操作步骤是通过qt框架进行实现的

案例

功能实现: 点击窗口上的按钮, 关闭窗口
功能分析:
- 按钮: 信号发出者 -> QPushButton 类型
- 窗口: 信号的接收者和处理者 -> QWidget 类型
在这里插入图片描述

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//  ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮
    connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}

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

不可以将第四个参数写为 &this->close,因为 &this->close 表示的是 MainWindow 类的成员函数指针,而 QPushButton::clicked 信号需要一个成员函数指针,而这个指针的类型是 void (MainWindow:😗)()(即没有参数且没有返回值的成员函数指针)。

自定义信号和槽

案例分析

假设要实现一个类GirlFriend发出hungry信号,一个类Me来接受信号进行处理。

  • 1、由于这两个是不同的类,所以应该提供一个窗口类对上面的这两个类进行包装
  • 2、在GirlFriend类中只需要声明信号,不需要实现,因为这是信号的发出者
  • 3、在Me类的槽函数不仅需要声明也需要实现

主窗口头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "girlfriend.h"
#include "me.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

public slots:
    void hungrySlot();

private:
    Ui::MainWindow *ui;
    GirlFriend *g_girl;
    Me *m_me;
};
#endif // MAINWINDOW_H

主窗口函数实现

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//  ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮

    g_girl=new GirlFriend;
    m_me=new Me;
    //这个hungry是自定义的不由Qt框架提供,需要使用者发射信号 >>>>>>> 窗口中实现
    connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);
    //>>>>>>>>>>>>>>提醒Qt框架有信号
    connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);

    connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}

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

void MainWindow::hungrySlot()
{
    //发射信号
    emit g_girl->hungry();
}

在这里插入图片描述

信号槽的拓展

  • 一个信号可以连接多个槽函数, 发送一个信号有多个处理动作
    需要写多个connect()连接
    槽函数的执行顺序是随机的, 和connect函数的调用顺序没有关系
  • 信号的接收者可以是一个对象, 也可以是多个对象
    一个槽函数可以连接多个信号, 多个不同的信号, 处理动作是相同的
    需要写多个connect()连接
  • 信号可以连接信号
connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::siganl-new);
  • 信号槽可以断开信号 --> 很少使用
disconnect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

信号连接信号案例

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//  ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮

    g_girl=new GirlFriend;
    m_me=new Me;
    //这个hungry是自定义的不由Qt框架提供
    connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);
    connect(g_girl,&GirlFriend::hungry,this,&MainWindow::eatSlot);

    //信号连接信号
    connect(ui->hungry,&QPushButton::clicked,g_girl,&GirlFriend::hungry);

    //信号连接槽函数
    //connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);

    connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}

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

void MainWindow::hungrySlot()
{
    //发射信号
    emit g_girl->hungry();
}

void MainWindow::eatSlot()
{
    qDebug()<<"喝尿";
}

在这里插入图片描述

信号槽的两种连接方式

Qt5中的处理方式

第二个和第四个参数是函数地址
在这里插入图片描述

Qt4中的处理方式

信号槽函数通过宏SIGNAL和SLOT转换为字符串类型
在这里插入图片描述

Qt5处理信号槽重载问题

signals:
    void hungry();
    void hungry(QString msg);
public slots:
 	//槽函数
 	void eat();
	 void eat(QString msg);

解决方案1:使用Qt4的信号与槽的机制(慎用,编译器不会报错如果你写错了)

    //Qt4的信号与槽
    connect(g_girl,SIGNAL(hungry()),m_me,SLOT(eat()));
    connect(g_girl,SIGNAL(hungry(QString)),m_me,SLOT(eat(QString)));

解决方案2:使用函数指针进行指定

    void(GirlFriend::*girl1)()=&GirlFriend::hungry;
    void(GirlFriend::*girl2)(QString)=&GirlFriend::hungry;
    void(Me::*point)(QString)=&Me::eat;
    void(Me::*pointt)()=&Me::eat;
    connect(g_girl,girl1,m_me,pointt);
    connect(g_girl,girl2,m_me,point);// >>>>> Qt5
    connect(g_girl,girl2,this,&MainWindow::eatSlot);// >>>>>> 信号是带参的而槽函数是不带参的 >>>> 直接就是执行eatSlot

案例

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//  ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮

    g_girl=new GirlFriend;
    m_me=new Me;
    //这个hungry是自定义的不由Qt框架提供
// >>>>>>>>>>>>>> Qt5处理重载
    void(GirlFriend::*girl1)()=&GirlFriend::hungry;
    void(GirlFriend::*girl2)(QString)=&GirlFriend::hungry;
    void(Me::*point)(QString)=&Me::eat;
    void(Me::*pointt)()=&Me::eat;
    connect(g_girl,girl1,m_me,pointt);
    connect(g_girl,girl2,m_me,point);// >>>>> Qt5
    connect(g_girl,girl2,this,&MainWindow::eatSlot);
//err
    //connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);// >>>>> Qt5
    //connect(g_girl,&GirlFriend::hungry,this,&MainWindow::eatSlot);

    //Qt4的信号与槽
    connect(g_girl,SIGNAL(hungry()),m_me,SLOT(eat()));
    connect(g_girl,SIGNAL(hungry(QString)),m_me,SLOT(eat(QString)));
    //信号连接信号
    //connect(ui->hungry,&QPushButton::clicked,g_girl,&GirlFriend::hungry);

    //信号连接槽函数
    connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);

    connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}

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

void MainWindow::hungrySlot()
{
    //发射信号
    g_girl->hungry();
    g_girl->hungry("粑粑");
}

void MainWindow::eatSlot()
{
    qDebug()<<"喝尿";
}

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

lambda表达式

lambda表达式–>匿名函数

[capture](params) opt -> ret {body;};
    - capture: 捕获列表
    - params: 参数列表
    - opt: 函数选项
    - ret: 返回值类型
    - body: 函数体
捕获列表: 捕获一定范围内的变量
	[] - 不捕捉任何变量
	[&] - 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)
	[=] - 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获)
	拷贝的副本在匿名函数体内部是只读的
	[=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo
	[bar] - 按值捕获 bar 变量, 同时不捕获其他变量
	[&bar] - 按引用捕获 bar 变量, 同时不捕获其他变量
	[this] - 捕获当前类中的this指针
		让lambda表达式拥有和当前类成员函数同样的访问权限
		如果已经使用了 & 或者 =, 默认添加此选项

简单案例

// 匿名函数的定义, 程序执行这个匿名函数是不会被调用的
[](){
    qDebug() << "hello, 我是一个lambda表达式...";
};

// 匿名函数的定义+调用:
int ret = [](int a) -> int
{
    return a+1;
}(100);  // 100是传递给匿名函数的参数

Qt中的应用

在这里插入图片描述

补充知识点

#include<iostream>
using namespace std;

class a
{
public:
    void print()
    {
        cout << "1" << endl;
    }
};

int main()
{
    a a;  // 创建对象
    a.print();
    // 声明成员函数指针并调用
    void (a:: * print_ptr)() = &a::print;  // 成员函数指针
    (a.*print_ptr)();  // 通过指针调用
}

在这里插入图片描述


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

相关文章:

  • 如何从头开始构建神经网络?(附教程)
  • WebRTC API分析
  • 类别变量分析——卡方独立性检验卡方拟合优度检验
  • 【C++】C++11特性(上)
  • Lucene 和 Elasticsearch 中更好的二进制量化 (BBQ)
  • 6.2 对角化矩阵(2)
  • Rust学习(二)——rust基础语法Ⅰ:
  • 【数据分享】2024年我国省市县三级的生活服务设施数量(46类设施/Excel/Shp格式)
  • 大数据实训室中,高职大数据可视化开发技术实训课程改革研究
  • 【机器学习】强化学习(1)——强化学习原理浅析(区分强化学习、监督学习和启发式算法)
  • 蓝桥杯-洛谷刷题-day2(C++)
  • Linux系统程序设计--2. 文件I/O
  • 大模型系列——LLAMA-O1 复刻代码解读
  • Spring Boot 的生命周期
  • 【进阶】Stable Diffusion 插件 Controlnet 安装使用教程(图像精准控制)
  • 探密 C++ STL — 深入理解 Stack 和 Queue 的实现与应用
  • 前端上传大文件,后端报错Content-Type ‘application/octet-stream‘ is not supported【解决】
  • Spring Boot2.x教程:(十二)日志分割后续
  • #渗透测试#SRC漏洞挖掘#Python自动化脚本的编写04之通过面向对象编程学生管理信息系统01
  • 20241108,LeetCode 每日一题,用 Go 计算字符串中最长无重复字符
  • 创元集团携手火山引擎,数据飞轮驱动美妆品牌数字化转型
  • 一个基于Zookeeper+Dubbo3+SpringBoot3的完整微服务调用程序示例代码
  • C语言中,“extern”关键字的含义与用法
  • 网页版五子棋——用户模块(服务器开发)
  • 金山云C++面试题及参考答案
  • jenkins配置前端自动部署