本节对应的视频讲解:B_站_链_接

https://www.bilibili.com/video/BV1mN4y137H6

信号和槽要建立连接,本质上是通过 `connect` 函数来连接实现的。

但是从写法或者操作上来说,有多种方式,以下总结了 5 种方式:

  • SIGNAL/SLOTQt4
  • 函数地址(Qt5
  • UI 设计师界面 - 转到槽
  • UI 设计师界面 - 信号槽编辑器
  • lambda 表达式

大家可根据自己的喜好自行选择。

接下来通过一个案例,来演示这 5 种使用方法:

首先,我们先把这个界面,快速地搭建起来

快速新建一个基于 QMainWindow 的工程:

切换到 mainwindow.ui 文件,按照如下方法,设计好界面:

  • 修改窗口标题为 “信号槽的 5 种连接方式”
  • 拖拽 5 个 QPushButton
  • 修改按钮的 name:btnMaxbtnNormalbtnMinbtnClosebtnSetWindowTitle
  • 布局窗口:垂直布局,以使得布局自适应窗口大小的变化
  • 修改按钮显示的文字,如上
  • 设置按钮字体大小为 15

经过以上几步,就完成了界面的布局,如下:

接下来就开始实现 5 种连接方式。

1. SIGNAL/SLOT(Qt4)


上一节的就是使用的这个方式

通过 SIGNAL/SLOT 这两个宏,将函数名以及对应的参数,转换为字符串,这是 Qt4 中使用的方式,当然在 Qt5 中也是兼容支持它的:

connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

其中:

  • sender:信号发送者
  • SIGNAL(signal()):发送的信号。SIGNAL 宏将信号转换成字符串
  • receiver:信号接收者
  • SLOT(slot()):槽函数。SLOT 宏将槽函数转换成字符串

这种方式,编译器不会做错误检查,即使函数名或者参数写错了,也可以编译通过,这样就把问题留在了运行阶段。

而我们编程开发的一个原则是尽可能早地发现并规避问题,因此这种方式不被推荐。

1.1 实现窗口最大化

下面通过这种方式,实现点击按钮,最大化窗口

mainwindow.cpp 的构造函数中,使用如下方式连接信号和槽:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 1.使用 SIGNAL/SLOT 的方式连接信号和槽connect(ui->btnMax, SIGNAL(clicked()), this, SLOT(showMaximized()));
}

此时,运行程序,点击按钮就可以最大化窗口了!

1.2 编译不检查

刚才说过,如果函数的名字写错了,在编译时不会报错,比如将 showMaximized 不小心写成了 showMaximize

点击【构建】菜单->【重新构建】,在【编译输出】窗口并不会报错

而在运行时,在【应用程序输出】窗口会看到报错,如下:

22:24:45: Starting E:\qt_project\build-HowToConnectSignalAndSlot-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\HowToConnectSignalAndSlot.exe...
QObject::connect: No such slot MainWindow::showMaximize() in ..\HowToConnectSignalAndSlot\mainwindow.cpp:10
QObject::connect:  (sender name:   'btnMax')
QObject::connect:  (receiver name: 'MainWindow')

2. 函数地址(Qt5)


这种方式中,信号和槽都使用函数的地址,如下:

connect(sender, &Sender::signal, receiver, &Receiver::slot);

其中:

  • sender:信号发送者
  • &Sender::signal:发送的信号
  • receiver:信号接收者
  • &Receiver::slot:槽函数

这种方式,编译时就会对函数类型,参数个数做检查。

2.1 实现窗口正常显示

下面通过这种方式,实现点击按钮,正常化显示窗口

mainwindow.cpp 的构造函数中,使用如下方式连接信号和槽:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 1.使用 SIGNAL/SLOT 的方式连接信号和槽connect(ui->btnMax, SIGNAL(clicked()), this, SLOT(showMaximized()));// 2.使用函数地址的方式连接信号和槽connect(ui->btnNormal, &QPushButton::clicked, this, &QMainWindow::showNormal);
}

此时,运行程序,点击按钮就可以正常化显示窗口了!

2.2 编译检查

如果函数的名字写错了,在编译时就会报错,比如将 showNormal 不小心写成了 showNorma,少写一个字母 L

在编辑器中就会飘红报错,如下:

mainwindow.cpp:14:58: No member named 'showNorma' in 'QMainWindow'; did you mean 'QMainWindow::showNormal'? (fix available)
qwidget.h:486:10: 'QMainWindow::showNormal' declared here

当然了,点击【构建】菜单->【重新构建】,在【编译输出】窗口也会会报错,如下:

..\HowToConnectSignalAndSlot\mainwindow.cpp: In constructor 'MainWindow::MainWindow(QWidget*)':
..\HowToConnectSignalAndSlot\mainwindow.cpp:14:71: error: 'showNorma' is not a member of 'QMainWindow'connect(ui->btnNormal, &QPushButton::clicked, this, &QMainWindow::showNorma);^~~~~~~~~
mingw32-make[1]: *** [Makefile.Debug:469: debug/mainwindow.o] Error 1

可见,使用这种方式,错误在代码编辑,程序编译阶段就会暴露出来,及早解决掉它。

这是 Qt 推荐的一种连接信号槽的方式!

3. UI设计师界面-转到槽


下面使用这种方式,实现点击 btnMin 按钮,最小化显示窗口

UI 设计师界面,右键单击 btnMin,然后选择【转到槽…】,弹出如下窗口:

选择 clicked(),即可生成并跳转到槽函数,即可在 mainwindow.hmainwindow.cpp 中生成对应的代码,如下:

// mainwindow.h
class MainWindow : public QMainWindow
{Q_OBJECT...private slots:void on_btnMin_clicked();
};// mainwindow.cpp
void MainWindow::on_btnMin_clicked()
{this->showMinimized();
}

此时会根据按钮的 name 自动生成对应的槽函数,对应关系为:

按钮的名字:btn1

槽函数的名字为:on_btn1_clicked

注意:如果修改了按钮的 name,那么槽函数的名字也要随之修改。

4. UI设计师界面-信号槽编辑器


下面使用这种方式,实现点击 btnClose 按钮,关闭窗口

进入到 UI 设计师界面,【View】菜单 ->【视图】->【Signal & Slots Editor】,在打开的信号槽编辑器中,点击绿色的加号+,

就可以连接信号和槽了:

此时,我们的代码文件并没有修改,而是修改了 mainwindow.ui 文件,如下:

我们在 1.4 小节时详细讲解过这个 ui 文件如何转换为编译器可以编译的 .h/.cpp 文件

没有看之前的视频的小伙伴,可以去观看《1.4 项目构建流程》

通过之前的讲解,我们知道,这个 ui 文件,最终会被转换为 ui_mainwindow.h 文件,打开就可以看到,转换后还是通过 connect 来连接的信号和槽,如下:

此时,运行程序,点击 btnClose 按钮,就可以关闭窗口了!

5. Lambda 表达式


槽函数还可以直接写成 lambda 表达式的形式。

C++11 引入了 lambda 表达式,用于定义并创建匿名的函数对象,可以使代码更加的简洁

Qt 是基于 C++ 的一个 GUI 框架,它完全支持 C++ 的语法,因此在 Qt 中也是可以使用 lambda 表达式的。

学习 Qt 多多少少都需要了解一些 C++ 的语法

不过如果你对 C++ 中的 lambda 表达式不了解,也不用担心,这里我们先复习一下 C++lambda 表达式的使用

lamda 表达式在现代语言中,非常的普遍。lamda 表达式简化了我们的一些语法,使得代码的表达更加的清晰,便于书写与阅读。

一些现代语言,比如 javapythonkotlin 等语言都是支持 lambda 表达式的

5.1 复习 lambda 表达式

C++ 中的 lambda 表达式,其实就是匿名函数,语法如下:

[capture](parameters) option -> return-type { body }

其中包含 5 个部分:

  • capture:捕获列表,可选

    捕捉列表总是出现在 lambda 表达式的开始。实际上,[]lambda 引出符,编译器根据该引出符判断接下来的代码是否是 lambda 表达式。

    捕捉列表能够捕获上下文中的变量,以在 lambda 表达式内使用,主要有如下几种情况:

    # 不捕获任何变量
    [] # 按引用捕获外部作用域中所有变量,在 lambda 表达式内使用
    [&]# 按值捕获外部作用域中所有变量,在 lambda 表达式内使用
    # 按值捕获的变量,在 lambda 表达式内是只读的,不能修改赋值
    [=]# 捕获外部作用域中所有变量,其中foo变量按引用捕获,其他的按值捕获
    [=, &foo] # 按值捕获bar变量,同时不捕获其他变量
    [bar] # 捕获当前类中的 this 指针
    # 捕获了 this 就可以在 lambda 中使用当前类的成员变量和成员函数。
    # 如果已经使用了 & 或者 =,就默认添加此选项。
    [this]
    
  • parameters:参数列表,可选

  • option:函数选项,可选

  • return-type:返回值类型,可选。没有返回值的时候也可以连同符号->一起省略

  • body:函数体

接下来,在 mainwindow.cpp 的构造函数中,逐一演示这 5 个部分的使用

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);...// 演示lambda表达式// 3.1 匿名函数的定义
#if 0[]() {qDebug() << "lambda...";};
#endif// 3.2 匿名函数的调用
#if 0[]() {qDebug() << "lambda...";}();
#endifint a =10;// 3.3 不捕获任何变量// Variable 'a' cannot be implicitly captured in a lambda with no capture-default specified
#if 0[]() {qDebug() << a;}();
#endif// 3.4 按引用捕获
#if 0[&]() {qDebug() << a++;    // 10}();qDebug() << a;          // 11
#endif// 3.5 按值捕获// 按值捕获的变量,在 lambda 表达式内是只读的,不能修改赋值
#if 0[=]() {// Cannot assign to a variable captured by copy in a non-mutable lambdaqDebug() << a++;}();
#endif// 3.6 按值捕获 + mutalbe 选项// 添加 mutable 选项,就可以在 lambda 内修改捕获的变量了// 并且=这种方式,是按值传递的,里面的修改,不会影响外边。
#if 0[=]() mutable {qDebug() << a++;    // 10}();qDebug() << a;          // 10
#endif// 3.7 参数// 添加 mutable 选项,就可以在 lambda 内修改捕获的变量了// 并且=这种方式,是按值传递的,里面的修改,不会影响外边。
#if 0[](int x, int y) {qDebug() << x + y;    // 3}(1, 2);
#endif// 3.8 返回值// 返回值可以省略,编译器会自动推断 lambda 表达式的返回值类型// 返回值省略时,也可以连同符号`->`一起省略
#if 0int sum = [](int x, int y) -> int {return x + y;}(1, 2);qDebug() << sum;    // 3
#endif#if 1int sum = [](int x, int y) {return x + y;}(1, 2);qDebug() << sum;    // 3
#endif
}

5.2 槽函数使用 lambda 表达式

有了以上 lambda 表达式的基本知识,将它作为槽函数,就水到渠成了,如下:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 1.使用 SIGNAL/SLOT 的方式连接信号和槽connect(ui->btnMax, SIGNAL(clicked()), this, SLOT(showMaximized()));// 2.使用函数地址的方式连接信号和槽connect(ui->btnNormal, &QPushButton::clicked, this, &::QMainWindow::showNormal);// 3.UI设计师界面-转到槽// 直接在UI界面,鼠标点击完成信号槽的连接// 4.UI设计师界面-信号槽编辑器// 直接在UI界面,鼠标点击完成信号槽的连接// 5. 使用lambda 表达式做槽函数connect(ui->btnSetWindowTitle, &QPushButton::clicked, this, [this]() {this->setWindowTitle("[连接信号槽的 5 种方式]");});
}

此时,运行程序,点击 btnSetWindowTitle 按钮,就可以修改窗口的标题了!

本节对应的视频讲解:B_站_链_接

https://www.bilibili.com/video/BV1mN4y137H6

【QT开发笔记-基础篇】| 第一章 QT入门 | 1.7 如何连接信号槽相关推荐

  1. 【QT开发笔记-基础篇】| 第二章 常用控件 | 2.12 表格控件 QTableWidget

    本节对应的视频讲解:B_站_链_接 QTableWidget 是 Qt 中的表格控件,可以行列的形式来展示数据 1. 属性和方法 QTableWidget 有很多属性和方法,完整的可查看帮助文档. 在 ...

  2. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.5 标准信号槽

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1vW4y1676Q 本节讲解信号和槽的概念,以及标准的信号槽 1. 什么是信号槽 1.1 信号 ...

  3. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.1 为什么要学习Qt

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1334y1776z Qt 是一个跨平台的 C++ 图形用户界面应用程序框架 Qt 为应用程序开发 ...

  4. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.2 搭建Qt开发环境

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1Pr4y1x7fh Qt 开发主要有两种开发环境 Qt Creator 它是 Qt 官方提供的开 ...

  5. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.4 项目构建流程

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1cW4y1y7Lw 在上一节课中,我们新建了第一个 Qt 工程,其中包括 5 个文件: Hell ...

  6. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.6 自定义信号槽

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1gA4y1d7gz 上节课,我们讲解了标准信号槽,标准信号槽中,信号和槽函数,都是 Qt 框架定 ...

  7. 【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.1 效果演示、技术点

    本节对应的视频讲解:B_站_视_频 https://www.bilibili.com/video/BV14P4y197pi Qt 中绘图用到的类是 QPainter,可以实现点.线.矩形.圆形.多边形 ...

  8. 【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.5 多段线、多边形

    本节对应的视频讲解:B_站_视_频 https://www.bilibili.com/video/BV1ZP4y1S7Ax 本节讲解如何绘制多段线.多边形 1. 相关的 API 直接查看官方的帮助文档 ...

  9. 【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.12 文本、图片

    本节对应的视频讲解:B_站_视_频 https://www.bilibili.com/video/BV1k14y1A7XL 本节讲解如何绘制文本 1. 相关的 API 直接查看官方的帮助文档,可以看到 ...

最新文章

  1. Xen虚拟化之一:Xen环境组件详解
  2. linux100day(day7)--用户管理和权限管理简单介绍
  3. JavaScript学习笔记:迷宫游戏
  4. 测试nignx php请求并发数,Nginx 高级篇(八)ab 压力测试即 nginx 的性能统计模块...
  5. OpenCV---高斯模糊(均值模糊的另一种)
  6. iOS逆向之自动化重签名
  7. Insufficient space for shared memory file 解决办法
  8. 推荐一些优质原创公众号
  9. 基于内容的图像检索技术:从特征到检索
  10. 笔记32 SpringMVC中使用静态资源、处理中文乱码
  11. 关于docker的日常操作(二)
  12. 从一个月2500没人要到大厂技术主管的编程之路|我的十年
  13. 为什么Next-Key Lock可以解决幻读问题
  14. 使用Mixamo_Converter重新定义根骨骼导入UE4
  15. Python实现自定义竖线的线型
  16. 用了两年的极点五笔,今天出问题了。。。
  17. 深天马A第一季度净利润为2.89亿元 同比减少35.4%
  18. 【创业笔记】团队建设--团队氛围的营造
  19. 系统安全测试要怎么做,详细来说说
  20. Linux文件系统:minix文件系统二进制分析3(硬链接与软链接)

热门文章

  1. 校园安防智能视频行为分析预警系统解决方案
  2. ptt评论超级计算机,【图片】来发一发PTT上台湾网友对《古剑奇谭》的评论吧!【古剑奇谭电视剧吧】_百度贴吧...
  3. 零基础自学软件测试我只用了105天,从月薪3000到15K, 我整理的超全学习指南!
  4. 20个在线听音乐网站
  5. 爬虫作业1:爬取肯德基餐厅地址查询
  6. 计算机地图概括的原理,地图概括的发展历史及现代的地图概括自动化
  7. IV XXSC-11
  8. JavaSwing | MouseEvent 鼠标事件
  9. FFA 2022 专场解读 - 流批一体 平台建设 AI 特征工程
  10. 企业需要DCIM工具来做什么?