Qt下普通成员函数和静态成员函数作为回调函数的实现(替代信号与槽)

文章目录

  • 前言
  • 一、使用信号与槽
  • 二、什么是回调函数
  • 三、使用普通成员函数作为回调函数
  • 四、使用静态成员函数作为回调函数
  • 五、示例完整代码
  • 总结


前言

在Qt中,使用信号与槽来实现不同对象之间的通信是非常方便的,这也是Qt框架中引以为傲的一项机制,这里对此不加以介绍,可以查看参考文章。在信号与槽之前,对象间的通信可以采用回调实现,接下来我们通过下面示例来学习如何将Qt下普通成员函数和静态成员函数作为回调函数来实现不同对象的通信,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、使用信号与槽

示例主界面是Widget,在其初始化函数中创建了子界面对象CallBackAdd,并在这里进行了信号与槽的连接,下面代码中可以看到信号与槽在Qt4和Qt5的写法,实现子界面点击后将输入的两个数值相加的结果发送到主界面显示出来:

下面的initWidget()函数是在主界面Widget类的构造函数中进行了调用:

//初始化界面
void Widget::initWidget()
{//创建子界面对象并显示m_addWidget = new CallBackAdd();m_addWidget->move(500,400);   //移到指定坐标防止遮挡主界面m_addWidget->show();//使用信号与槽//connect(m_addWidget,SIGNAL(signal_addNum(int)),this,SLOT(slot_addNum(int)));   //Qt4写法connect(m_addWidget,&CallBackAdd::signal_addNum,this,&Widget::slot_addNum);    //Qt5写法
}

主界面Widget类的h文件中添加槽函数:

private slots:void slot_addNum(int addNum);

Widget类的cpp文件中进行定义:

//槽函数
void Widget::slot_addNum(int addNum)
{ui->le_num->setText(QString::number(addNum));
}

子界面CallBackAdd类的h文件中添加信号:

signals:void signal_addNum(int addNum);

CallBackAdd类的cpp文件中点击按钮后发送信号:

//按钮点击槽函数
void CallBackAdd::on_pb_add_clicked()
{int num_1 = ui->le_num_1->text().toInt();int num_2 = ui->le_num_2->text().toInt();int addNum = num_1 + num_2;//发送信号emit signal_addNum(addNum);
}

关于信号与槽的更多介绍可以查看该文章:C++ Qt开发:如何使用信号与槽

二、什么是回调函数

上面使用信号与槽实现了不同对象之间的通信,下面让我们先了解一下回调函数,再使用回调函数来替代信号与槽实现通信。

这里引用参考文章中的内容:函数指针的调用,即是一个通过函数指针调用的函数;如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就说这是回调函数。

参考文章:什么是回调函数?为什么要使用回调函数?如何使用回调函数?

三、使用普通成员函数作为回调函数

为什么类的普通成员函数不能作为回调函数去注册?因为普通成员函数中隐含着所属类的this指针,如果将普通成员函数注册给对方,但对方使用这个函数指针时,就会发生参数列表匹配的问题。这时候我们可以通过function和bind实现将普通成员函数作为回调函数进行调用,其用法可以参考:C++11 bind和function用法

主界面Widget类的h文件中添加普通成员函数的声明:

private://普通成员函数作为回调函数void getAddResult(int addResult);

Widget类的cpp文件中进行定义:

//初始化界面
void Widget::initWidget()
{...//使用回调函数(普通成员函数),通过function和bind实现m_addWidget->setCallBackFun(std::bind(&Widget::getAddResult,this,_1));
}//回调函数的定义(普通成员函数)
void Widget::getAddResult(int addResult)
{ui->le_num->setText(QString::number(addResult));
}

子界面CallBackAdd类的h文件中添加相关头文件和设置回调函数的接口函数等:

#include <iostream>
#include <functional>using namespace std;
using namespace std::placeholders;   //占位符_N所在的命名空间//声明一个function类型的可调用对象(可理解为函数指针)
typedef std::function<void(int)> CallBack;class CallBackAdd : public QWidget
{...
public://设置回调函数的接口函数void setCallBackFun(CallBack fun);private:CallBack m_callbackFun;
}

CallBackAdd类的h文件中进行定义:

//设置回调函数
void CallBackAdd::setCallBackFun(CallBack fun)
{m_callbackFun = fun;
}//按钮点击槽函数
void CallBackAdd::on_pb_add_clicked()
{int num_1 = ui->le_num_1->text().toInt();int num_2 = ui->le_num_2->text().toInt();int addNum = num_1 + num_2;//使用回调m_callbackFun(addNum);
}

四、使用静态成员函数作为回调函数

静态成员函数不包含this指针,可以直接将静态成员函数注册给对方,但是本示例的静态成员函数中有调用ui对象,同样因为不含this指针,所以不能直接访问ui对象,这里定义一个m_widget来间接使用this指针。

主界面Widget类的h文件中添加普通成员函数的声明:

private://声明一个静态的Widget类变量static Widget *m_widget;//使用static函数作为回调函数static void getAddNum(int addNum);

Widget类的cpp文件中进行定义:

#include "widget.h"//类外初始化静态的Widget类变量
Widget *Widget::m_widget = nullptr;Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//赋值m_widget变量m_widget = this;//初始化界面this->initWidget();
}//初始化界面
void Widget::initWidget()
{...//使用回调函数(静态成员函数)m_addWidget->setCallBackFun(getAddNum);
}//回调函数的定义(静态成员函数)
void Widget::getAddNum(int addNum)
{//静态成员函数并不能直接访问ui对象(普通成员函数)//此处使用m_widget变量来实现静态成员函数操作ui对象m_widget->ui->le_num->setText(QString::number(addNum));
}

子界面CallBackAdd类与第三部分中的代码一致。

五、示例完整代码

1.callbackadd.h

#ifndef CALLBACKADD_H
#define CALLBACKADD_H#include <QWidget>
#include <iostream>
#include <functional>using namespace std;
using namespace std::placeholders;   //占位符_N所在的命名空间//声明一个function类型的可调用对象(可理解为函数指针)
typedef std::function<void(int)> CallBack;namespace Ui {
class CallBackAdd;
}class CallBackAdd : public QWidget
{Q_OBJECTpublic:explicit CallBackAdd(QWidget *parent = nullptr);~CallBackAdd();//设置回调函数的接口函数void setCallBackFun(CallBack fun);signals:void signal_addNum(int addNum);private slots:void on_pb_add_clicked();private:Ui::CallBackAdd *ui;CallBack m_callbackFun;
};#endif // CALLBACKADD_H

2.callbackadd.cpp

#include "callbackadd.h"
#include "ui_callbackadd.h"CallBackAdd::CallBackAdd(QWidget *parent) :QWidget(parent),ui(new Ui::CallBackAdd)
{ui->setupUi(this);this->setAttribute(Qt::WA_QuitOnClose,false);   //设置随父窗口关闭
}CallBackAdd::~CallBackAdd()
{delete ui;
}//设置回调函数
void CallBackAdd::setCallBackFun(CallBack fun)
{m_callbackFun = fun;
}//按钮点击槽函数
void CallBackAdd::on_pb_add_clicked()
{int num_1 = ui->le_num_1->text().toInt();int num_2 = ui->le_num_2->text().toInt();int addNum = num_1 + num_2;//发送信号//emit signal_addNum(addNum);//使用回调m_callbackFun(addNum);
}

3.widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "callbackadd.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void initWidget();private slots:void slot_addNum(int addNum);private:Ui::Widget *ui;CallBackAdd *m_addWidget;private://普通成员函数作为回调函数void getAddResult(int addResult);//声明一个静态的Widget类变量static Widget *m_widget;//使用static函数作为回调函数static void getAddNum(int addNum);};
#endif // WIDGET_H

4.widget.cpp

#include "widget.h"
#include "ui_widget.h"//类外初始化静态的Widget类变量
Widget *Widget::m_widget = nullptr;Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//赋值m_widget变量m_widget = this;//初始化界面this->initWidget();
}Widget::~Widget()
{delete ui;
}//初始化界面
void Widget::initWidget()
{//创建子界面对象并显示m_addWidget = new CallBackAdd();m_addWidget->move(500,400);   //移到指定坐标防止遮挡主界面m_addWidget->show();//使用信号与槽//connect(m_addWidget,SIGNAL(signal_addNum(int)),this,SLOT(slot_addNum(int)));   //Qt4写法//connect(m_addWidget,&CallBackAdd::signal_addNum,this,&Widget::slot_addNum);   //Qt5写法//使用回调函数(普通成员函数),通过function和bind实现//m_addWidget->setCallBackFun(std::bind(&Widget::getAddResult,this,_1));//使用回调函数(静态成员函数)m_addWidget->setCallBackFun(getAddNum);
}//槽函数
void Widget::slot_addNum(int addNum)
{ui->le_num->setText(QString::number(addNum));
}//回调函数的定义(普通成员函数)
void Widget::getAddResult(int addResult)
{ui->le_num->setText(QString::number(addResult));
}//回调函数的定义(静态成员函数)
void Widget::getAddNum(int addNum)
{//静态成员函数并不能直接访问ui对象(普通成员函数)//此处使用m_widget变量来实现静态成员函数操作ui对象m_widget->ui->le_num->setText(QString::number(addNum));
}

5.callbackadd.ui
请添加图片描述

6.widget.ui
请添加图片描述


总结

通过以上这个示例可以看到在Qt中使用使用回调函数也是可以实现不同对象间的通信,这里的示例比较简单,主要让大家对回调函数有个简单的认识,实现回调函数还有其它的方式,详细的内容可以看一下参考文章。(在Qt下开发,信号与槽是真香啊~~)


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考文章:
C++ Qt开发:如何使用信号与槽
什么是回调函数?为什么要使用回调函数?如何使用回调函数?
C++11 bind和function用法
五种将c++类的成员函数用作回调函数的方法——史上最全、最简!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/294219.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NVMe介绍

NVMe介绍 1 概述2 操作原理2.1 Queue基本原理2.2 Admin与I/O Queue2.3 Submission与Completion Queue2.4 Submission与Completion Queue对应关系 3 多路径I/O和命名空间共享3.1 1Port1Controller3.2 1Port2Controller3.3 2Port2Controller3.4 SR-IOV 本文属于《 NVMe协议基础系…

钓鱼与木马实践(仅供参考不可实践)

声明:内容仅供学习&#xff0c;请勿违法使用&#xff0c;违者后果自负 一.部署云服务器 购买一台云服务器,Windows&#xff08; 中文 &#xff09;版本即可 华为云官网&#xff1a;https://www.huaweicloud.com/ 登录后进入控制台购买完成后远程登录云服务器 二.部署WEB运行…

Linux内核编码规范

学习linux内核或者linux驱动的人应该先掌握内核编码规范&#xff0c;这样才能更好的驾驭linux内核、驱动。 下面就从这几个方面讲解一下linux内核编码规范。 注释风格、排版风格、头文件风格、变量定义、宏定义、函数 1 注释风格 1.1 注释的原则是有助于对程序的阅读和理解&…

一文了解提示工程(Prompt Engineering)

引言 在机器学习的世界里&#xff0c;有一句众所周知的话&#xff0c;“机器学习模型的好坏取决于您为其提供的训练数据。” 它指出了数据质量在您从这些算法中获得的结果中发挥的关键作用。 在使用生成式 AI 模型时&#xff0c;这一想法也很重要 - 无论它们生成文本、代码还…

第一次记录QPSK,BSPK,MPSK,QAM—MATLAB实现

最近有偶然的机会学习了一次QPSK防止以后忘记又得找资料&#xff0c;这里就详细的记录一下 基于 QPSK 的通信系统如图 1 所示&#xff0c;QPSK 调制是目前最常用的一种卫星数字和数 字集群信号调制方式&#xff0c;它具有较高的频谱利用率、较强的抗干扰性、在电路上实现也较为…

dotnet命令创建C#项目,VSCode打开

在命令行中创建项目并运行 1.首先安装.net 下载地址:.NET | 构建。测试。部署。 2.在 cmd 控制台输入 dotnet --vesion 检查版本号是否正常 3.我用git bash环境输入命令创建项目 // 创建文件夹 mkdir MyVSCode // 进入该文件夹 cd MyVSCode/ // 创建控制台项目 dotnet …

华为Harmony——ArkTs语言

文章目录 一、简单示例二、声明式UI描述创建组件无参有参数 配置属性配置事件配置子组件 三、自定义组件基本用法基本结构成员函数/变量 一、简单示例 我们以一个具体的示例来说明ArkTS的基本组成。如下图所示&#xff0c;当开发者点击按钮时&#xff0c;文本内容从“Hello Wo…

css 实现满屏升空的气球动画

最终实现效果 demo放在最后了。。。。 问题一 怎么实现满屏气球&#xff1f;简单理解就是多个气球的合并&#xff0c;难道要写多个盒子吗&#xff1f;确实是这样子&#xff0c;但可以有更好的办法&#xff0c;其实就是通过原生操作多个盒子生成&#xff0c;所以只需要实现一个…

【接口测试】如何定位BUG的产生原因

我们从在日常功能测试过程中对UI的每一次操作说白了就是对一个或者多个接口的一次调用&#xff0c;接口的返回的内容(移动端一般为json)经过前端代码的处理最终展示在页面上。http接口是离我们最近的一层接口&#xff0c;web端和移动端所展示的数据就来自于这层&#xff0c;那么…

Web组态可视化编辑器-by组态

演示地址&#xff1a; http://www.by-lot.com http://www.byzt.net web组态可视化编辑器&#xff1a;引领未来可视化编辑的新潮流 随着网络的普及和快速发展&#xff0c;web组态可视化编辑器应运而生&#xff0c;为人们在网络世界中创建和编辑内容提供了更加便捷的操作方式。这…

【OCR识别】PaddleHub实现验证码识别

文章目录 前言无脑安装使用PaddleHub寻找预训练模型库完整代码效果图 前言 前面有篇文章介绍了 【网站验证码识别】 &#xff0c;但是其是利用 tesseract 工具的命令行来实现图片内容的识别。 这几天我突然想起&#xff0c;大学时参加百度 AI 比赛用过其 PaddleHub 框架&…

【Amazon 实验②】使用缓存策略及源请求策略,用于控制边缘缓存的行为及回源行为

文章目录 1. 了解缓存策略和源请求策略1.1 使用缓存键和缓存策略 实验&#xff1a;使用CloudFront缓存策略和缓存键控制缓存行为 接上一篇文章【Amazon 实验①】使用 Amazon CloudFront加速Web内容分发&#xff0c;我们现在了解和配置如何使用缓存策略及源请求策略&#xff0c;…