Qt 信号与槽

2023-11-20

Qt 信号与槽

在这章节里,我们学习 Qt 的信号与槽,这里分一个章节来学习这个 Qt 的信号与槽,可见
这个信号与槽有多么重要。在学习 Qt 的过程中,信号与槽是必不可少的部分,也是 Qt 编程的
基础,是 Qt 编程的一大创新(其实与 C#的事件很相似,编程都是类似的),Qt 的信号与槽在

Qt4 时或者更早前已经出现,并不是属于哪个版本的。只是 Qt4 与 Qt5 的信号槽连接的写法有
些区别。本教程对 Qt4 的信号与槽连接写法不做讲解。

同时,由此章节开始,我们将不使用 Qt Designer 的方式进行开发,也可以在新建项目时把

*ui 文件不勾选。为什么不用 Qt Designer 方式开发程序了呢?Qt Designer 方式开发程序简单,
优点就是方便快捷,ui 文件的优点就是能比较直观快捷的看到整体的布局。

但是缺点也很明显!简单的一两个部件还是可以的,但是控件多了就不好管理,每次都要
打开 ui 文件添加新控件,不好用代码管理!读者也无从知道笔者是如进行界面布局的,且信号
槽的连接方式是生成代码之后才能在 setupUi 函数里才能看到,或者需要进入 Ui 设计器里的信
号槽模式里才能看到信号槽的连接,这样十分之不方便!没有代码那么直观!所以统一用代码
绘界面,可以锻炼我们的布局能力,和代码逻辑能力!

本章的内容如下:
5.1 小节里我们学习 Qt 信号与槽机制的定义。
5.2 小节开始我们就学习如何在项目里定义我们的信号与槽的创建和使用方法。
Qt 信号与槽机制

信号与槽(Signal & Slot)是 Qt 编程的基础,也是 Qt 的一大创新。因为有了信号与槽的
编程机制,在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。

信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标
单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的
CurrentIndexChanged() 信号。
GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射
哪些信号,合理地去响应和处理这些信号就可以了。

槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++函数是一样的,可以
定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。
槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数
被自动执行。

信号与槽关联是用 QObject::connect() 函数实现的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
connect() 是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用
时可以忽略前面的限定符,所以可以直接写为:
connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

其中,sender 是发射信号的对象的名称,signal() 是信号名称。信号可以看做是特殊的函
数,需要带括号,有参数时还需要指明参数。receiver 是接收信号的对象名称,slot() 是槽函数
的名称,需要带括号,有参数时还需要指明参数。
SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符
串。例如,在 4.1 小节的项目 02_designer_example 的 ui_mainwindow.h 文件(ui_mainwindow.h

文件是编译后产生的,位于 build-02_designer_example-Desktop_Qt_5_12_9_GCC_64bit-Debug

文件夹目录下)中,在 setupUi() 函数中有如下的语句:
QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(close()));

其作用就是将 pushButton 按钮的 clicked() 信号与窗体(MainWindow)的槽函数 close() 相
关联,这样,当单击 pushButton 按钮(就是界面上的“X”按钮)时,就会执行 MainWindow

的 close() 槽函数。在这里我们就可以解决 4.1.3 小节的中部分疑问了。我们使用第一种方法没
看到信号与槽是怎么连接的,实际上它在 UI 文件编译后在生成的代码 ui_mainwindow.h 里!

关于信号与槽的使用,有以下一些规则需要注意:

一个信号可以连接多个槽,例如:

connect(pushButton, SIGNAL(clicked()), this, SLOT(hide()); 
connect(pushButton, SIGNAL(clicked()), this, SLOT(close()); 

这是当一个对象 pushButton 的被单击时,所在窗体有两个槽进行响应,一个 hide()用于隐
藏主窗体,一个 close 用于关闭主窗体。这里只是举个例子,实际上当执行 close()后,hide()这
个槽已经没有什么意义了,因为已经程序退出了,但是实际它有执行,因为它连接在 close()的
前面。当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。

当信号和槽函数带有参数时,在 connect()函数里,要写明参数的类型,但可以不写参数名
称。

多个信号可以连接同一个槽,例如在 02_designer_example 里,我们再拖 2 个 pushButton 到
设计的窗体里。同时也让它按 4.1 小节项目里的第一种方法连接信号与槽,把三个按钮的 clicked()

信号都连接到 close()槽函数里。编译后可以在 ui_mainwindow.h 这个文件里的 setupUi()函数里,
有如下的信号槽连接语句。

connect(pushButton,SIGNAL(clicked()),this,SLOT(close())); 
connect(pushButton_2,SIGNAL(clicked()),this,SLOT(close())); 
connect(pushButton_3,SIGNAL(clicked()),this,SLOT(close())); 

这样,当任何一个 pushButton 被单击时,都会执行 close()函数,进而关闭或者退出程序。

一个信号可以连接另外一个信号(说明了 connect 万物皆可连,非常好用!),例如:
connect(pushButton, SIGNAL(objectNameChanged(QString)),this, SIGNAL(windowTitelChan
ged(QString)));

这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。

严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。
如果不匹配,会出现编译错误或运行错误。

在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT(特别重要)。

当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。
只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。

总结如下图,可以看到发送者与发送的信号是在一起的,接收者与接收的信号/槽是在一起
的。它们不能在 connect()方法里写乱顺序!由发送者发送出信号到接收者用信号/槽接收。
在这里插入图片描述

信号槽连接的方法已经讲解了。这里只是稍稍提一下,断开连接的方法,初学者基本用不
到断开连接的操作。使用 disconnect()。disconnect(),这个方法重载了好几个函数,解开格式如
下。
bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const
char *method)

 断开一切与 myObject 连接的信号或槽。

disconnect(myObject, 0, 0, 0);

相当于非静态重载函数:
myObject->disconnect();

 断开所有连接到特定信号的东西。

disconnect(myObject, SIGNAL(mySignal()), 0, 0);
相当于非静态重载函数:
myObject->disconnect(SIGNAL(mySignal()));

 与指定的接收者断开连接。
disconnect(myObject, 0, myReceiver, 0);

相当于非静态重载函数:
myObject->disconnect(myReceiver);

信号与槽机制是 Qt GUI 编程的基础,使用信号与槽机制可以比较容易地将信号与响应代
码关联起来。

如何在项目里创建信号

我们先新建一个项目,并把项目命名为 03_signal_slot_example,如果还不会新建项目,请
回到 3.6 小节查看项目如何建立的。只是新建项目命名为 03_signal_slot_example,同时取消勾
选*ui 文件(为什么取消?可以在第五章章节开头处找理由),其他步骤不变。
由于信号只需声明,无需定义。所以我们只需要在 mianwindow.h 里声明信号即可。代码如
下,如下图黑色加粗部分代码就是创建的信号。这里创建一个 void pushButtonTextChang
ed();信号,定义信号最好是贴合信号本身的含义。笔者定义这个信号的意思是按钮的文本发
生改变后的 signal。

mainwindow.h 添加信号后的代码

1 #ifndef MAINWINDOW_H 

2 #define MAINWINDOW_H 

3 

4 #include <QMainWindow> 

5 /* 引入 QPushButton */ 

6 #include <QPushButton> 

7 

8 class MainWindow : public QMainWindow 

9 { 

10 Q_OBJECT 

11 

12 public: 

13 MainWindow(QWidget *parent = nullptr); 

14 ~MainWindow(); 

15 

16 signals: 

17 /* 声明一个信号,只需声明,无需定义 */ 

18 void pushButtonTextChanged(); 

19 

20 }; 

21 #endif // MAINWINDOW_H 

第 16 至 18 行,声明一个信号 void pushButtonTextChanged();,可以看到信号无需

public 等关键字修饰。

5.3 如何在项目中创建槽

创建槽的方法也很简单,也是直接在 mianwindow.h 里直接声明槽,在 mianwindow.cpp 里
实现槽的定义,声明槽必须写槽的定义(定义指函数体的实现),否则编译器编译时将会报错。
槽有以下特点:

  1. 槽可以是任何成员函数、普通全局函数、静态函数
  2. 槽函数和信号的参数和返回值要一致

根据上面的槽特点,由于我们在 5.2 小节里声明了信号 void pushButtonTextChanged();

所以我们声明的槽函数必须是无返回值类型 void,和无需参数。所以声明槽的代码如下。此外
我们还声明一个 QPushButton 对象 pushButton。对象 pushButton 可以写成简写 btn。这个根据个
人习惯即可!简写的名称建议不要让人看不懂即可!同时还声明一个按钮点击的槽。

mainwindow.h 添加槽函数后的代码

1 #ifndef MAINWINDOW_H 

2 #define MAINWINDOW_H 

3 

4 #include <QMainWindow> 

5 /* 引入 QPushButton */ 

6 #include <QPushButton> 

7 

8 class MainWindow : public QMainWindow 

9 { 

10 Q_OBJECT 

11 

12 public: 

13 MainWindow(QWidget *parent = nullptr); 

14 ~MainWindow(); 

15 

16 

17 signals: 

18 /* 声明一个信号,只需声明,无需定义 */ 

19 void pushButtonTextChanged(); 

20 

21 public slots: 

22 /* 声明一个槽函数 */ 

23 void changeButtonText(); 

24 

25 /* 声明按钮点击的槽函数 */ 

26 void pushButtonClicked(); 

27 

28 private: 

28 /* 声明一个对象 pushButton */ 

30 QPushButton *pushButton; 

31 }; 

32 #endif // MAINWINDOW_H 

第 23 行,声明一个槽函数 void changeButtonText();。
第 26 行,声明了一个槽函数 void pushButtonClicked();。
第 31 行,声明了一个 QPushButton 对象 pushButton。
在 mainwindow.cpp 里 实 现 声 明 的 槽 函 数 void changeButtonText(); 和 void
pushButtonClicked();。同时还实例化了 pushButton 对象。代码如下。

mainwindow.cpp 添加槽的实现代码

1 #include "mainwindow.h" 

2 

3 MainWindow::MainWindow(QWidget *parent) 

4 : QMainWindow(parent) 

5 { 

6 /* 设置窗体的宽为 800,高为 480 */ 

7 this->resize(800,480); 

8 

9 /* 实例化 pushButton 对象 */ 

10 pushButton = new QPushButton(this); 

11 

12 /* 调用 setText()方法设定按钮的文本 */ 

13 pushButton->setText("我是一个按钮"); 

14 } 

15 

16 MainWindow::~MainWindow() 

17 { 

18 

19 } 

20 

21 /* 实现按钮点击槽函数 */ 

22 void MainWindow::pushButtonClicked() 

23 { 

24 /* 使用 emit 发送信号 */ 

25 emit pushButtonTextChanged(); 

26 } 

27 

28 /* 实现按钮文本改变的槽函数 */ 

29 void MainWindow::changeButtonText() 

30 { 

31 /* 在槽函数里改变按钮的文本 */ 

32 pushButton->setText("被点击了!"); 

33 } 

第 7 行,设置程序窗体的大小,假若不设置,窗体为最小分辨率。这里设置宽为 800,高
为 480。刚好是正点原子 RGB LCD 屏里其中一个分辨率。实际开发需要以硬件的实际分辨率
开发即可。本教程都是以 800*480 分辨率开发。不建议使用低于这个分辨率开发,分辨率太低,
显示的内容过少。
第 10 行,实例化 pushButton 对象,在堆中实例化,并指定父对象为 this。因为我们在 mai
nwindow.h 里声明的是指针类型的对象。实际上 QPushButton(this)的原型是 QPushButton
(QWidget *parent = nullptr)。在 C++基础里第 2.2.3 小节里就已经学过重载,实际上 QP
ushButton 类中还有下面两种初始化的方法。这也是 C++在 Qt 里重载的体现。
QPushButton(const QString &text, QWidget *parent = nullptr)
QPushButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr)

在 22 行和 29 行里,实现了槽方法。

5.4 如何在项目中连接信号与槽

5.2 和 5.3 小节只是声明了信号和定义槽,要在项目中连接信号与槽。完成连接的代码如下。
信号槽连接的代码如下。
connect(pushButton, SIGNAL(clicked()), this, SLOT(pushButtonClicked()));
connect(this, SIGNAL(pushButtonTextChanged()), this, SLOT(changeButtonText()));

注意,发送信号的对象,和接收的信号的对象。因为我们 pushButtonClicked()是本类里定
义的槽,所以用 this 来接收。同理,pushButtonTextChanged()也是本类定义的信号。所以发送
者写成 this。changeButtonText()也是本类的槽函数,所以接收槽的对象也是 this。很多初学者不
了解这里的信号的发送者和槽的接收者,究竟该写谁。我们要细读上面的代码和 5.1 小节的信
号槽机制的定义慢慢理解。

在 mainwindow.cpp 中信号槽连接的代码如下。

mainwindow.cpp 实现连接信号槽

1 #include "mainwindow.h" 

2 

3 MainWindow::MainWindow(QWidget *parent) 

4 : QMainWindow(parent) 

5 { 

6 /* 设置窗体的宽为 800,高为 480 */ 

7 this->resize(800,480); 

8 

9 /* 实例化 pushButton 对象 */ 

10 pushButton = new QPushButton(this); 

11 

12 /* 调用 setText()方法设定按钮的文本 */ 

13 pushButton->setText("我是一个按钮"); 

14 

15 /* 信号与槽连接 */ 

16 connect(pushButton, SIGNAL(clicked()), this, 
SLOT(pushButtonClicked())); 

17 connect(this, SIGNAL(pushButtonTextChanged()), this, 
SLOT(changeButtonText())); 

18 } 

19 

20 MainWindow::~MainWindow() 

21 { 

22 

23 } 

24 

25 /* 实现按钮点击槽函数 */ 

26 void MainWindow::pushButtonClicked() 

27 { 

28 /* 使用 emit 发送信号 */ 

29 emit pushButtonTextChanged(); 

30 } 

31 

32 /* 实现按钮文本改变的槽函数 */ 

33 void MainWindow::changeButtonText() 

34 { 

35 /* 在槽函数里改变按钮的文本 */ 

36 pushButton->setText("被点击了!"); 

37 } 

第 16、17 行,连接信号与槽,整个流程就是当点击了按钮,然后触发了 pushButtonCli
cked(),pushButtonClicked()槽里发送 pushButtonTextChanged()信号,changeBut
tonText()槽响应 pushButtonTextChanged()信号,我们在 changeButtonText()槽实现
响应的动作(事件)。最终的实现效果是按钮的文本由“我是一个按钮”被点击时变成“被点击
了!”。
编译程序及运行后,未点击按钮前如下
在这里插入图片描述
点击按钮后。
在这里插入图片描述
上面的程序虽然简单,但是我们也最终实现了自定义的信号与槽。

5.5 学会使用 Qt 类的信号与槽

Qt 里有大量的信号与槽,都是 Qt 自定义好的。基本够我们使用,如果没有找到想要的信
号与槽,我们就可以按 5.2~5.4 小节自定义信号与槽的方法去定义自己的信号和槽了。那么我
们该如何使用 Qt 信号与槽呢?
要想使用 Qt 的信号与槽,那么我们必须知道有哪些信号与槽。在 5.4 小节的代码里。
connect(pushButton, SIGNAL(clicked()), this, SLOT(pushButtonClicked()));
如下图示,按住 Ctrl 键,再点击 clicked(),进入 clicked()这个信号的定义处。在这里插入图片描述
进入 QPushButton 的定义处,我们看到 QPushButton 不止 clicked 信号,还有其他信号,也
有 QPushButton 的槽函数(返回上一步按 Alt + 方向左键)。在这里我们只是简单的看了如何在
已知信号和槽里查找其他信号与槽。实际上在开发中我们经常需要使用 Qt 帮助文档来查看 Qt

定义的信号与槽。我们将在下一章里讲解 Qt 帮助文档的使用,帮助文档里面就有如何查看 Qt

的信号与槽等等。
在这里插入图片描述

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

Qt 信号与槽 的相关文章

随机推荐

  • discuz 论坛配置 QQ/163 网易邮箱

    步骤 在 discuz 后台的 站长 邮件设置 里按如下配置 SMTP 服务器固定 163 网易填 ssl smtp 163 com QQ 邮箱则填 ssl smtp qq com 端口 465 验证 勾选 配置完成后 会进行测试验证 发信
  • clamp 函数

    clamp 函数 返回范围内的一个数值 可以使用 clamp 函数将不断增加 减小或随机变化的数值限制在一系列的值中 float clamp float minnumber float maxnumber float parameter 最
  • 简单用用flex和bison

    简单用用flex和bison 参考博文 词法 语法分析器简介 定义 flex bison 文件间关系 具体例子 例1 输入name age时触发 输出name is age years old 例2 输入带有括号的满足乘法加法的表达式 输出
  • 有关ajax 不走回调函数的问题解析

    ajax是设置的返回值明明是json格式 但是返回值是json格式却接收不了 非要设置成text格式才可以接收的到 这是我的jQuery代码 function addSku id var m m id val var p p id val
  • JDBC(Java DataBase Connectivity)

    JDBC 目录 JDBC 简介 JDBC结构步骤 API接口 DriverManager Conection Statement ResultSet PreparedStatement 简介 JDBC是使用Java语言操作关系数据库的一套A
  • maven安装和环境变量配置

    myeclipse自带maven Maven4MyEclipse 创建项目 新建Web Projects项目 在新建的页面上打上maven的勾 新建的项目里会多出个pom xml文件 为项目添加依赖包 右键项目 选择Maven4MyEcli
  • 多对一查询

    是这样的 首先学生表中有三个属性 前两个属性要出现在结果集中 第三个属性哦用于查找教师的名字 然后呢 用resultMap重新处理 将老师的名字重新对应为学生表的第三个属性 其实这样做有局限 多对一查询 SQL语句 SELECT s id
  • python中文件的操作

    gt gt gt f open home ceshi mmm txt w w 为读写 gt gt gt f write zuoshouzhiyue n 写入数据 记得加 n gt gt gt f tell 当前在文件中的位置 14 gt g
  • QToolButton和QPushButton的区别

    用代码实践了一下QPushButton和QToolButton的差异 include widget h include
  • Mathematica函数大全

    一 运算符及特殊符号 Line1 执行Line 不显示结果 Line1 line2 顺次执行Line1 2 并显示结果 name 关于系统变量name 的信息 name 关于系统变量name 的全部信息 command 执行Dos 命令 n
  • 《权力的游戏》最终季上线!谁是你最喜爱的演员?这里有一份Python教程

    译者 刘畅 编辑 琥珀 出品 AI科技大本营 id rgznai100 权力的游戏 最终季已于近日开播 对于全世界翘首以待的粉丝们来说 其最大的魅力就在于 无法预知的人物命运 那些在魔幻时代的洪流中不断沉浮的人们 将会迎来怎样的结局 近日
  • DS18B20的原理及实例代码(51单片机、STM32单片机)

    一 DS18B20介绍 DS18B20数字温度传感器是DALLAS公司生产的单总线器件 用它来组成一个测温系统具有线路简单 体积小 在一根通信线上可以挂很多这样的数字温度传感器 十分方便 温度传感器种类众多 应用在高精度 高可靠性的场合时D
  • c语言程序for循环处设断点,C语言程序设计-循环.ppt

    C语言程序设计 循环 C语言程序设计 循环结构 while循环结构 例 求1 100之和 即 注意事项 如果循环体内只有一条语句 则可以不用大括号 语法上并没有要求一定要存在循环初始条件的设定 也没有要求循环条件中的变量必须在循环体内改变
  • 使用JTDS连接sqlserver数据库

    Java连接SQL Server 2000数据库时 有两种方法 1 通过Microsoft的JDBC驱动连接 此JDBC驱动共有三个文件 分别是mssqlserver jar msutil jar和msbase jar 但是Microsof
  • IDEA 查看Springboot单元测试代码覆盖率报错

    报错信息 D resource java jdk 1 8 261 bin java exe ea javaagent C Users 镜 AppData Local JetBrains IntelliJIdea2020 2 testAgen
  • 软路由自建iptv服务器,LEDE软路由 iPTV 实现任意端口看电视的方法

    摘 要 1 光猫直接连接电脑 超级管理员进入光猫后台修改光猫为桥接模式 把IPTV 的VLAN ID绑定到跟宽带一样的数据端口 如下图 2 软路由 我们以6网口的来演示 进入Lede后台 系统 进阶设置 配置dnsmasq添加代码 dhcp
  • 互联网寒冬?应届生还应该加入么?

    大家都在各种唱衰互联网行业 下面从真实的示例来分析一下 还能否加入这个行业 互联网企业现状 互联网企业地域分布 从业者从一线城市逐渐向低线扩展 对新一线及低线城市的青睐度上升 腾讯地域扩张 腾讯业务版图 阿里地域扩张 阿里业务版图 字节地域
  • PhpStorm为什么值得推荐?

    智能编码辅助 PhpStorm 是一个 PHP IDE 它实际上 获取 您的代码 它支持 PHP 5 3 5 4 5 5 5 6 7 0 7 1 7 2 提供动态错误预防 最佳自动完成和代码重构 零配置调试以及扩展的 HTML CSS 和J
  • sql ntext數據類型字符替換

    ntext數據類型字符替換 2011 08 21 塗聚文 create table tt sid INT IDENTITY 1 1 cont ntext go insert into tt cont values N fd sad fdsa
  • Qt 信号与槽

    Qt 信号与槽 在这章节里 我们学习 Qt 的信号与槽 这里分一个章节来学习这个 Qt 的信号与槽 可见 这个信号与槽有多么重要 在学习 Qt 的过程中 信号与槽是必不可少的部分 也是 Qt 编程的 基础 是 Qt 编程的一大创新 其实与