QT-信号与槽机制学习笔记

2023-11-16

一、标准信号和槽

  • 信号:各种事件
  • 槽:响应信号的动作

 当某个事件发生之后,某个按钮被点击之后,他就会发出一个被点击的信号

 某个对象接收到这个信号之后,就会做一些相关的处理动作(slot)

 要想让一个对象收到另一个对象发出的信号,这是需要建立连接connect

#include "widget.h"
#include<QPushButton>
#include"mypushbutton.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QPushButton *btn = new QPushButton("按钮1",this);

    // 按钮
    // 被点击
    // 窗口
    // 关闭

    // 建立四者的关系 按钮  被点击  窗口 关闭
    
    // connect(信号发送者,信号,信号接收者,槽)
    connect(btn,&QPushButton::clicked,this,&Widget::close);

}

Widget::~Widget()
{
}

  • 信号发送者
  • 信号
  • 信号接收者

二、自定义信号与槽

  • 自定义信号

    • 函数声明在类头文件的signals域下面
    • void类型的函数 没有返回值
    • 可以有参数,也可以重载
    • 只有声明,没有实现定义
    • 触发信号 emit obj->sign(参数…)
  • 自定义槽

    • 函数声明在类头文件的public/private/protected slots域下面(qt4以前版本)qt5就可以声明在类的任何位置,还可以是静态成员函数,全局函数、lambda表达式
    • void 类型的函数 没有返回值
    • 可以有参数 也可以重载
    • 不仅有声明 还得有实现

2.1 信号与槽的案例-无参数

下课了 老师饥饿 学生请客吃饭

teacher.h 添加一个饥饿信号 不需要实现 函数

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    
    // 添加信号  只有声明 没有实现  信号就是一个函数
    void hungry();

};

#endif // TEACHER_H


teacher.cpp

#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent)
{

}

student.h 自定义槽函数形式 需要实现

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:

public slots:

    // 自定义槽 学生请吃饭   函数形式 需要实现
    void treat();

};

#endif // STUDENT_H


student.cpp 槽函数需要在cpp文件中进行实现

#include "student.h"
#include<QDebug>

Student::Student(QObject *parent) : QObject(parent)
{

}

// 函数声明的实现  使用类作用域符号进行引入
void Student::treat()
{
    qDebug()<<"Stduent treat teacher";
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include"student.h"
#include"teacher.h"

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    
    // 自定义触发信号  在里面发射信号
    void classOver();

private:
    
    // 引入成员  私有化
    Teacher *pT;
    Student *pS;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 根据私有成员 新建两个对象
    pT = new Teacher(this);
    pS = new Student(this);

    // 建立连接
    connect(pT,&Teacher::hungry,pS,&Student::treat);

    this->classOver();// 调用  触发信号
}

Widget::~Widget()
{
}


// 发射自定义信号
void Widget::classOver()
{
    // 触发老师饥饿的信号
    emit pT->hungry();
}


2.2 有参数的信号与槽案例

带参数的自定义信号和槽函数,就声明函数的时候带上参数就行,老师说他饿了,说要吃黄焖鸡,学生就请客吃黄焖鸡

  • 使用函数指针进行赋值
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 根据私有成员 新建两个对象
    pT = new Teacher(this);
    pS = new Student(this);
    
    // 使用函数指针赋值  让编译器挑选符合类型的函数
    void (Teacher::*teacher_qString)(QString) = &Teacher::hungry;
    void (Student::*student_qString)(QString) = &Student::treat;

    // 建立连接
    connect(pT,teacher_qString,pS,student_qString);

    this->classOver();// 调用  触发信号
}

Widget::~Widget()
{
}


// 发射自定义信号
void Widget::classOver()
{
    // 触发老师饥饿的信号  然后触发槽函数
    emit pT->hungry();

    // 发射带参数的信号
    emit pT->hungry("黄焖鸡");
}

  • 使用static_cast 强制进行转换 也是让编译器自动挑选符合类型的函数
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 根据私有成员 新建两个对象
    pT = new Teacher(this);
    pS = new Student(this);

    // 使用函数指针赋值  让编译器挑选符合类型的函数
    void (Teacher::*teacher_qString)(QString) = &Teacher::hungry;
    void (Student::*student_qString)(QString) = &Student::treat;

    // 建立连接
//    connect(pT,teacher_qString,pS,student_qString);

    // 使用static_cast 来转换无参数的函数
    connect(pT,static_cast<void (Teacher::*)()>(&Teacher::hungry),pS,static_cast<void (Student::*)()>(&Student::treat));

    this->classOver();// 调用  触发信号
}

Widget::~Widget()
{
}


// 发射自定义信号
void Widget::classOver()
{
    // 触发老师饥饿的信号  然后触发槽函数
    emit pT->hungry();

    // 发射带参数的信号
    emit pT->hungry("黄焖鸡");
}

参数二义性问题:

  • 使用函数指针赋值,让编译器自动挑选符合类型的函数
  • 使用static_cast强制转换 让编译器自动挑选符合类型的函数

三、信号和槽的扩展

  • 一个信号可以连接多个槽
    一个信号建立了多个connect,那么当信号发射的时候,槽函数的调用顺序:随机

  • 一个槽可以连接多个信号

  • 信号可以连接信号
    connect(第一个信号发送者,第一个信号,第二个信号发送者,第二个信号)

  • 信号可以断开连接,disconnect
    connect 参数怎么填写,disconnect就怎么填写

  • 信号和槽的参数关系,必须满足以下两点

    • 信号和槽函数的参数类型必须对应
    • 信号和槽函数的参数个数不需要一致,信号函数参数个数>= 槽函数参数个数

四、Qt4的信号和槽函数

  • 使用两个宏SIGNAL、SLOT
  • connect使用不一样,信号和槽函数声明差不多
  • connect(信号发送者,SIGNAL(函数原型),信号接收者,SLOT(函数原型))
connect(pT,SIGNAL(hungry(QString)),pS,SLOT(treat(QString)));// 传入的信号与槽都是带有参数的函数

不存在二义性问题

SIGNAL和SLOT宏的原理,就是将后边的参数转换成字符串, 类似于#define toStr(arg)|#arg -> “arg”

好处:不存在二义性问题
坏处:写错函数名,编译不会出错

五、QDebug的输出转义问题

  • QString 转成char *
    qDebug()<<"Stduent treat teacher with "<<what.toUtf8().data();
    
  • 使用qDebug().noquote()
    qDebug().noquote()<<"Student treat teacher with"<<what;
    

六、lambda表达式

定义匿名函数对象,简化编程工作,Lambda表达式的基本构成:

[局部变量捕获列表]、(函数参数)、函数额外属性设置opt、函数返回值->retype、{函数主体}

[capture](parameters)opt->retType
{

}

6.1 简单的案例

// 下面的代码 捕获 a b 变量 输出10 和 20

  • 下面的代码是值传递 传递参数
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;

    // 传入参数 将a b 都捕获进来

    [a,b]()
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b;// 输出10 20
    }();

}

Widget::~Widget()
{
    delete ui;
}
  • 下面的代码是引用传递
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;

    // 传入参数 将a b 都捕获进来  引用传递

    [&a,&b]()
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b;// 输出10 20
    }();

}

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

使用引用传递,可以在Lambda表达式中更改变量,但是默认情况下值传递捕获进行来的就是const

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


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;

    // 传入参数 将a b 都捕获进来  引用传递
    [a,b]() mutable
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b;// 输出10 20
        
        // 进行修改  但是改不了
        a = 30;
        b= 40;
    }();

    qDebug()<<a<<b;// 输出10 20
}

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


使用=将所有的变量全部拷贝进来

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


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;
    int c = 0;
    int d = 9;

    // 传入参数 将a b 都捕获进来  引用传递
    // 使用 = 将所有的参数
    [=]() mutable
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b<<c<<d;// 输出10 20


    }();

    qDebug()<<a<<b;// 输出10 20
}

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

[&]全部使用引用传递

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


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;
    int c = 0;
    int d = 9;

    // 传入参数 将a b 都捕获进来  引用传递
    // 使用 = 将所有的参数   & 全部使用引用传递
    [&]() mutable
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b<<c<<d;// 输出10 20


    }();

    qDebug()<<a<<b;// 输出10 20
}

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

[=,&b] 除了B是引用传递 其他的都是值传递

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


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;
    int c = 0;
    int d = 9;

    // 传入参数 将a b 都捕获进来  引用传递
    // 使用 = 将所有的参数   & 全部使用引用传递
    
    
    // 除了 b是值传递  其他的都是引用传递
    [=,&b]() mutable
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b<<c<<d;// 输出10 20


    }();

    qDebug()<<a<<b;// 输出10 20
}

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

6.2 lambda表达式

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


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);// 初始化窗口

    // 局部变量捕获
    int a = 10;
    int b = 20;
    int c = 0;
    int d = 9;

    // 传入参数 将a b 都捕获进来  引用传递
    // 使用 = 将所有的参数   & 全部使用引用传递


    // 除了 b是值传递  其他的都是引用传递
    [=,&b]() mutable
    {
        qDebug()<<"Hello Lambda";
        qDebug()<<a<<b<<c<<d;// 输出10 20


    }();

    qDebug()<<a<<b;// 输出10 20

    // 创建一个按钮
    QPushButton *btn = new QPushButton("按钮1",this);// 新建一个对象

    connect(btn,&QPushButton::clicked,[&](){
        qDebug()<<a<<b;
        this->close();
    });
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT-信号与槽机制学习笔记 的相关文章

随机推荐

  • string类型数组java_Java string类和数组的相关函数总结

    一 string类 1 字符串查找 1 str indexOf substr 返回substr首次在str里出现的索引 str 任意字符串对象 substr 要搜索的字符串 2 str lastIndexOf substr 返回substr
  • 洛谷P1011 [NOIP1998 提高组] 车站题解

    斐波那契数列 题目描述 火车从始发站 称为第1站 开出 在始发站上车的人数为a 然后到达第2站 在第2站有人上 下车 但上 下车的人数相同 因此在第2站开出时 即在到达第3站之前 车上的人数保持为a人 从第3站起 包括第3站 上 下车的人数
  • 拒绝摆烂!C语言练习打卡第四天

    博客主页 小王又困了 系列专栏 每日一练 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 选择题 1 第一题 2 第二题 3 第三题 二 编程题 1 第一题 2 第二题 前言 在前面我们学习完C语言的所以知识 当然练习巩固也不能
  • 万维网(www)

    万维网 www 是互联网中使用最广泛的一种应用 是一个超大规模线上信息储藏所 以链接的形式为用户提供信息检索服务 万维网的核心作用 使得信息在网上自由传输 万维网提供分布式的信息检索服务 箭头代表以链接的形式跳转到其他页面 这种方式使得一个
  • 【Maven】单元测试、统计、覆盖率相关插件使用介绍

    maven surefire plugin maven surefire plugin是maven执行单元测试的插件 不显性配置也可以直接使用 这个插件的surefire test命令会默认绑定maven执行的test阶段 执行结束后 默认
  • Mysql数据库的环境搭建【详细】

    作者简介 大学机械本科 野生程序猿 学过C语言 玩过前端 还鼓捣过嵌入式 设计也会一点点 不过如今痴迷于网络爬虫 因此现深耕Python 数据库 seienium JS逆向 安卓逆向等等 目前为全职爬虫工程师 学习的过程喜欢记录 目前已经写
  • ASM插桩:学完ASM Tree api,再也不用怕hook了

    背景 对于ASM插桩来说 可能很多人都不陌生了 但是大多数可能都停留在core api上 对于现在市面上的一些插桩库 其实很多都用tree api进行编写了 因为tree api的简单与明了的特性 也越来越成为许多开源库的选择 ASM有两套
  • 【STM32CubeMX】位置式PID调节控制输出电压(超详解)

    本文将借助STM32CubeMX来配置ADC DMA DAC USART 并利用PID位置式算法实现对输出电压进行AD采集通过PID算法调节DAC 获取到我们想要的电压值 讲解的主要知识 何为PID以及为何需要PID STM32CubeMX
  • 计算机含金量最高的证书

    第一种证书 计算机技术与软件专业资格考试证书 计算机技术与软件专业资格考试证书 是由国家人力资源和社会保障部 工业和信息化部领导的国家级考试 该考试分为 5 个专业类别 并分设了高 中 初级专业资格考试 共 28 个资格的考核 也是用人单位
  • Open3D(C++) 根据索引提取点云

    目录 一 功能概述 1 主要函数 2 源码 二 代码实现 三 结果展示 本文由CSDN点云侠原创 原文链接 爬虫网站自重 把自己当个人 一 功能概述 1 主要函数 std shared ptr
  • 添加CSS样式的三种方法与CSS的注释

    目录 三种使用 CSS 的方法 外部 CSS 实例 mystyle css 内部 CSS 实例 行内 CSS 实例 多个样式表 实例 实例 层叠顺序 CSS 注释 实例 实例 实例 HTML 和 CSS 注释 实例 当浏览器读到样式表时 它
  • R_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server;

    error Error R NOT SUPPORTED AUTH MODE Client does not support authentication protocol requested by server MySQL 8 has su
  • C++性能优化系列——矩阵转置(四)OpenMP并行计算

    本系列之前的篇章都是基于单线程处理 实际工程中 通过多线程对程序进行并行化往往是最简单且直接有效的优化手段 本篇以C 性能优化系列 矩阵转置 三 内存填充避免缓存抖动 中优化好的程序为Base版本 通过OpenMP技术 对程序进一步做并行化
  • 下面几款接口测试工具,工作中都有用的那些?

    下面几款接口测试工具 工作中都有用的那些 1 Fiddler Fiddler是一款功能强大的接口测试软件 它可以帮助用户抓取 修改和重放HTTP HTTPS请求 是一款可视化的网络调试利器 它可以支持HTTP协议和HTTPS协议 支持GET
  • 初识pnpm

    初识pnpm 介绍 pnpm和npm yarn一样 都是包管理器 但是pnpm节约磁盘空间并且安装很快 所有的报会存储在硬盘的同一个位置 多个项目使用了同一个包时 在pnpm中他们是公用的 只会存储一遍 下次需要用到这个包时就会从硬盘中查找
  • FISCO BCOS 八、快速入门truffle(通过Ganache部署)

    目录 快速入门 Truffle 创建项目工程 项目结构 使用测试 编译合约 通过 Ganache 部署合约 常见问题 问题1 Error Could not find artifacts for home wu MetaCoin test
  • Android JetPack学习笔记-DataStore

    通过键值对存储 以异步 一致的事务方式存储数据克服了SharedPreferences的一些缺点 基于kotlin协程的Flow实现 并且可以对SP数据进行迁移 以protobuffer协议进行存储 速度更快 效率更高 使用 引用 impl
  • 实践练习五(可选):对 OceanBase 做性能测试

    第六期直播实践练习 可选 对一个OB集群 带 OBProxy 进行Benchamrk测试 环境准备 由于手上正好有7台物理机 在作业三中会使用OBD直接部署了2 2 2架构的OceanBase集群 这里直接拿来进行TPC C测试 机器信息如
  • Kettle——表输出步骤异常处理方式探究

    开源ETL工具Kettle transformation中的多数步骤都是支持定义错误处理的 为了保证transformation脚本的健壮性 我们会在关键的步骤上进行异常捕获处理 本篇文章以TableOutput步骤来探究kettle异常处
  • QT-信号与槽机制学习笔记

    QT 信号与槽机制学习笔记 一 标准信号和槽 二 自定义信号与槽 2 1 信号与槽的案例 无参数 2 2 有参数的信号与槽案例 三 信号和槽的扩展 四 Qt4的信号和槽函数 五 QDebug的输出转义问题 六 lambda表达式 6 1 简