QT 信号和槽 通过自定义信号和槽沟通 如何自定义槽和信号的业务,让它们自动关联 自定义信号功能

2024-06-10 17:28

本文主要是介绍QT 信号和槽 通过自定义信号和槽沟通 如何自定义槽和信号的业务,让它们自动关联 自定义信号功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

通过信号和槽机制通信,通信的源头和接收端之间是松耦合的:

  • 源头只需要顾自己发信号就行,不用管谁会接收信号;
  • 接收端只需要关联自己感兴趣的信号,其他的信号都不管;
  • 只要源头发了信号,关联该信号的接收端全都会收到该信号,并执行相应的槽函数。

源头和接收端是非常自由的,connect 函数决定源头和接收端的关联关系,并会自动根据信号里的参数传递给接收端的槽函数。
因为源头是不关心谁接收信号的,所以 connect 函数一般放在接收端类的代码中,或者放在能同时访问源端和接收端对象的代码位置。

编辑好之后保存界面,回到代码编辑模式,打开 widget.h,添加处理按钮 clicked 信号的槽函数,和新的自定义的信号 SendMsg: 

 

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();signals:    //添加自定义的信号void SendMsg(QString str);  //信号只需要声明,不要给信号写实体代码public slots:   //接收按钮信号的槽函数void ButtonClicked();private:Ui::Widget *ui;
};#endif // WIDGET_H

signals: 就是信号代码段的标志,这个标志不带 public 、protected、private 等前缀,那是因为信号默认强制规定为公有类型,这样才能保证其他对象能接收到信号。
我们定义了 SendMsg 信号,带一个 QString 参数,这个声明与普通函数声明类似。注意信号只是一个空壳,只需要声明它,而不要给它写实体代码。自定义信号的全部代码就是头文件这里的两行(包括 signals: 行),不需要其他的。signals: 标识的代码段只能放置信号声明,不能放其他任何东西,普通的函数或变量、槽函数都不要放在这里。

public slots: 是公有槽函数代码段的标志,定义了 ButtonClicked 槽函数,接收按钮被点击的信号,这个槽函数以后会触发我们自定义的信号。槽函数代码段也只能放槽函数声明的代码,不要把其他的东西放在这个代码段里。

下面来编写 widget.cpp 里面的代码,实现发送我们自定义信号的槽函数,并和按钮的信号关联起来:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//关联connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(ButtonClicked()));
}Widget::~Widget()
{delete ui;
}
//槽函数
void Widget::ButtonClicked()
{//用 emit 发信号emit SendMsg( tr("This is the message!") );
}

 在 Widget 构造函数里,我们将按钮的 clicked 信号关联到槽函数 ButtonClicked,当按钮被点击时,ButtonClicked 会自动被调用。
ButtonClicked 里面只有一句代码,就是

emit SendMsg( tr("This is the message!") );

emit 是发信号的关键字,然后接下来就与调用函数是一样的格式,SendMsg 里面放置我们想传递的字符串参数。除了 emit 字样,触发信号就与函数调用一样。这样简单一句就实现了触发信号的过程,同之前所说的,源端就顾自己发信号,至于谁接收 SendMsg 信号,源端是不管的。
Widget 窗体代码就是上面那么多,发送我们自定义的 SendMsg 信号的过程如下图所示:

 对于上图左半段,按钮的点击信号和相应的槽函数我们之前两节已经用过多次了,这个不是关注的重点。重点就是在主窗体槽函数里面,我们发出了自定义的信号 SendMsg ,谁来接收它呢?

接下来我们造一个接收 SendMsg 信号的类对象和槽函数,并将收到的字符串参数弹窗显示。我们先为该项目添加一个新的类,并编写接收 SendMsg 信号的槽函数。
打开 QtCreator 菜单“文件”-->“新建文件或项目”,在“新建”对话框里,左边部分选择“C++”,中间部分选 “C++ Class”,如下图所示:

 然后点击右下角 Choose,进入新建 C++ 类的向导界面,将 Class name 修改为 ShowMsg,基类选择 QObject,其他的就用自动填充的,选择基类 QObject 之后,会自动包含相应头文件。要使用信号和槽机制,必须直接或间接从 QObject 类派生,我们这里是直接从 QObject 派生了子类 ShowMsg:

 然后点击“下一步”,进入项目管理界面:

 这里就按照默认的值,不用修改,自动添加到项目 qobjcom.pro 里面,版本控制默认是没有。点击“完成”,稍等一会,QtCreator 就会生成好 ShowMsg 类的两个文件 showmsg.h 和 showmsg.cpp,并添加到项目里。

接下来,我们编辑 showmsg.h ,声明接收 SendMsg 信号的槽函数 RecvMsg:

#ifndef SHOWMSG_H
#define SHOWMSG_H#include <QObject>class ShowMsg : public QObject
{Q_OBJECT
public:explicit ShowMsg(QObject *parent = 0);~ShowMsg();signals:public slots://接收 SendMsg 信号的槽函数void RecvMsg(QString str);
};#endif // SHOWMSG_H

 

RecvMsg 槽函数声明的参数类型和返回类型要与 SendMsg 信号保持一致,所以参数是 QString,返回 void。然后我们编辑 showmsg.cpp,实现 RecvMsg 槽函数:
#include "showmsg.h"
#include <QMessageBox>ShowMsg::ShowMsg(QObject *parent) : QObject(parent)
{}ShowMsg::~ShowMsg()
{}//str 就是从信号里发过来的字符串
void ShowMsg::RecvMsg(QString str)
{QMessageBox::information(NULL, tr("Show"), str);
}

添加头文件 <QMessageBox> 包含之后,我们添加槽函数 RecvMsg 的实体代码,里面就是一句弹窗的代码,显示收到的字符串。QMessageBox::information 函数第一个参数是父窗口指针,设置为 NULL,代表没有父窗口,就是在系统桌面直接弹窗的意思。
信号和槽机制有三步,一是有源头对象发信号,我们完成了;第二步是要有接收对象和槽函数,注意,上面只是类的声明,并没有定义对象。我们必须定义一个接收端的对 象,然后才能进行第三步 connect。

编辑项目里 main.cpp,向其中添加代码,定义接收端对象,然后进行 connect:

#include "widget.h"
#include <QApplication>
#include "showmsg.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;   //①主窗体对象,内部会发送 SendMsg 信号ShowMsg s;  //②接收端对象,有槽函数 RecvMsg//③关联,信号里的字符串参数会自动传递给槽函数QObject::connect(&w, SIGNAL(SendMsg(QString)), &s, SLOT(RecvMsg(QString)));//显示主界面w.show();return a.exec();
}

 首先添加 "showmsg.h" 头文件包含,然后在主窗体对象 w 定义之后,定义了接收端对象 s。主窗体对象 w 会发 SendMsg 信号,接收端 s 有对应的槽函数 RecvMsg,这样完成了信号和槽机制的头两步。接下来第三步就是调用关联函数 QObject::connect,将源头对象、信号、接收端对象、槽函数关联。connect 函数是通用基类 QObject 里面定义的,之前用 connect 函数都没有加类前缀,是因为在 QObject 派生类里面自动继承了 connect 函数,不需要额外的前缀。在 main 函数里,需要手动加 QObject:: 前缀来调用 connect 函数。
关联完成之后,一旦用户点击主窗体里的按钮,我们自定义的 SendMsg 信号就会发出去,然后 接收端对象 s 里的槽函数就会执行,并且信号里的字符串也会自动传递给 RecvMsg 槽函数,然后会出现弹窗显示传递的字符串。
这个示例的运行效果如下图所示:

 

本小节需要大家学习的就是右半段的部分,我们在主窗体 ButtonClicked 函数里触发自定义的信号 SendMsg,然后通过 connect 函数关联,自动调用了接收端对象 s 的槽函数 RecvMsg,并弹窗显示了传递的字符串。

也许有读者会问,费这么大劲,为什么不直接在 ButtonClicked 里面弹窗?那不简单多了?
因为本小节的目的不是弹窗,而是为了展现自定义信号和槽函数的代码写法,理解信号和槽机制的运行流程。以后遇到复杂多窗口的界面程序,在多个窗体对象之间就可以用 上图示范的流程,来进行通信、传递数据。 

这篇关于QT 信号和槽 通过自定义信号和槽沟通 如何自定义槽和信号的业务,让它们自动关联 自定义信号功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1048803

相关文章

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录