信号信号槽

三、信号槽

  1. 概念

信号和槽是两种函数,这是Qt在C++基础上新增的特性,类似于其他技术中的回调的概念。

信号槽通过程序员提前设定的“约定”,可以实现对象之间的通信,有两个先决条件。

  • 通信的对象都是在QOBject类中派生出来的。

QOBject类是Qt所有类型的基类。

  • 类中要有Q_OBJECT宏。

  1. 函数原型

信号槽需要在使用进行“约定”。这个约定也称为连接。

【例子】:如果新周考试考100分,那么宵宾请新周吃饭。

// 参数1:发射者,表示因发起的对象【新周】
// 参数2:信号函数,表示因发起的动作【考100】
// 参数3:接收者,表示果发起的对象【宵宾】
// 参数4:槽函数,表示果发起的动作【请吃饭】
connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)[static]

  1. 实现

为了学习,把信号槽分为三种实现的方式。

  • 自带信号→自带槽
  • 自带信号→自定义槽
  • 自定义信号

3.1 自带信号→自带槽

这种连接方式是最简单的,因为信号函数和槽函数都是Qt内置的,只需要在文档中查询出函数后,使用connect函数连接即可。

【例子】:点击按钮,关闭窗口。

// 点击按钮,发射此信号
void QAbstractButton::​clicked(bool checked = false)[signal]

// 关闭窗口槽函数
bool QWidget::​close()[slot]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn; // 成员变量
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{// 设置窗口的宽高resize(500,500);    btn = new QPushButton("关闭",this);// 设置按钮位置
    btn->move(200,250);// 连接信号槽【点击按钮,关闭窗口】// 参数1:按钮对象// 参数2:点击信号函数clicked// 参数3:窗口对象// 参数4:关闭窗口槽函数closeconnect(btn,SIGNAL(clicked()),this,SLOT(close()));
}Dialog::~Dialog()
{// 堆内存回收
    delete btn;
}

3.2 自带信号→自定义槽

Qt不可能内置所有执行的动作代码,特别是一些复杂的动作,需要开发者手动编写槽函数,这种方式是所有连接方式中使用最多的。

槽函数实际上是一种特殊的成员函数,在声明的时候权限的作用主要是修饰其作为普通成员函数的使用效果,不影响信号槽的连接效果。

【例子】:点击按钮,向右边和下边移动窗口10个相似,同时输出当前窗口的坐标。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);
    ~Dialog();private:QPushButton *btn; // 成员变量private slots:
    void mySlot(); // 小驼峰命名:第一个单词小写,其他单词首字母大写};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口的宽高
    resize(500,500);    btn = new QPushButton("关闭",this);
    // 设置按钮位置
    btn->move(200,250);
    // 连接信号槽
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}// 自定义槽函数实现
void Dialog::mySlot()
{
    // 先获取当前的坐标
    int x = this->x();
    int y = this->y();    // 移动坐标位置
    move(x+10,y+10);    // 输出当前位置
    qDebug() << x+10 << y+10;
}Dialog::~Dialog()
{
    // 堆内存回收
    delete btn;
}

3.3 自定义信号

为了讲解,强行使用自定义信号,并非问题的最优解,主要学习写法。

信号函数是一种非常特殊的函数,因为只有声明,没有定义。即没有函数体,因此无法调用,只能使用emit关键字发射。

【例子】:点击按钮,关闭窗口。

3.1 的信号连接方式。

本节中强行在中间加一层自定义信号的转发过程。

上图中→表示信号槽连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QPushButton *btn;private slots:
    void mySlot();    // 自定义信号
signals:
    void mySignal();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 创建按钮对象
    btn = new QPushButton("关闭",this);
    btn->move(100,150);    // 信号槽连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));    // 第二次槽函数连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}Dialog::~Dialog()
{
    delete btn;
}

4、信号槽传参

【例子】点击按钮,按钮上显示点击的次数。

 QPushButton的按钮文字属性为text : QString,可以使用setter更改按钮文字。

// 设置按钮显示的文字
// 显示的文字,QString类型
void	setText(const QString & text)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    QPushButton *btn;private slots:
    void mySlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}Dialog::~Dialog()
{
    delete btn;
    delete ui;
}void Dialog::mySlot()
{
    // 静态局部变量
   static int count = 0;
   count++;
   // 类型转换 int → QString
   QString text = QString::number(count);   // 更改按钮文字
   btn->setText(text);}

把上面的案例强行改为信号槽传参:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    QPushButton *btn;private slots:
    void mySlot();
    void mySlot2(int); // 与mySignal(int)连接的自定义槽函数
signals:
    void mySignal(int); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(int)),
            this,SLOT(mySlot2(int)));
}Dialog::~Dialog()
{
    delete btn;
    delete ui;
}void Dialog::mySlot()
{
    // 静态局部变量
    static int count = 0;
    count++;    emit mySignal(count);
}void Dialog::mySlot2(int count)
{
    // 类型转换 int → QString
    QString text = QString::number(count);    // 更改按钮文字
    btn->setText(text);
}

需要注意的是:

  • 理论上可以传递多个参数,建议最多写两个参数,多了会很冗余。如果非得传递多个参数,可以定义成一个类,传递对象。
  • 信号的参数个数必须大于等于槽函数参数个数。
  • 信号的参数类型要与槽的参数相匹配。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Demo
{
public:
    int a = 10;
    int b = 20;
    double c = 3.23;
    float d = 1.1;
};class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn;private slots:
    void mySlot();  // 自定义槽函数
    void mySlot2(const Demo &); // 与mySignal(int)连接的自定义槽函数signals:
    void mySignal(const Demo &); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn = new QPushButton("0",this);
    btn->move(150,150);connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));connect(this,SIGNAL(mySignal(const Demo &)),this,SLOT(mySlot2(const Demo &)));
}void Dialog::mySlot()
{Demo demo;// 发射带参数的自定义信号函数
    emit mySignal(demo);
}void Dialog::mySlot2(const Demo &demo)
{qDebug() << demo.a;qDebug() << demo.b;qDebug() << demo.c;qDebug() << demo.d;
}Dialog::~Dialog()
{
    delete btn;
}

5、对应关系

5.1 一对多

一对多指的是一个信号可以连接多个槽函数。

对于一对多的连接关系,可以合并为一对一,因为槽函数也是一个成员函数,可以整合到一个槽函数中进行连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:
    QPushButton *btn1; // 一对多
    QPushButton *btn2; // 一对一private slots:void mySlot1();void mySlot2();void mySlot3();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn1 = new QPushButton("一对多",this);
    btn1->move(200,200);// 一对多的优势就是可以灵活处理每个对应关系// 例如可以断开某个信号槽的连接// 断开连接的函数与连接槽函数一样,只需要在函数名称前面加disdisconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));// 一对多connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));// 一对一
    btn2 = new QPushButton("一对一",this);
    btn2->move(200,250);connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot3()));disconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));
}Dialog::~Dialog()
{}void Dialog::mySlot1()
{qDebug() << "A" ;
}
void Dialog::mySlot2()
{qDebug() << "B" ;
}void Dialog::mySlot3()
{mySlot1();mySlot2();
}

5.2 多对一

多对一指的是多个信号连接同一个槽函数,多对一的问题在于槽函数无法直接判断那个信号触发的槽函数调用,但是可以通过sender函数在槽函数中获得发射者对象,通过对象的比对判断来源。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();
private:
    QPushButton *btn1;
    QPushButton *btn2;private slots:// 多对一的槽函数void btnClickedSlot();};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(500,500);
    btn1 = new QPushButton("多对一A",this);
    btn1->move(200,200);    btn2 = new QPushButton("多对一B",this);
    btn2->move(200,250);// 多对一connect(btn1,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));connect(btn2,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{delete btn1;delete btn2;
}void Dialog::btnClickedSlot()
{if(btn1 == sender()){qDebug() << "A" ;}else if(btn2 == sender()){qDebug() << "B" ;}else{qDebug() << "对象错误" ;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

springboot212球队训练信息管理系统

球队训练信息管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装球队训练信息管理系统软件…

代理IP为什么会有延迟?

在当今信息高速发展的时代&#xff0c;随着代理IP在数据采集、网络安全和匿名浏览等领域的应用&#xff0c;已成为网络技术中不可或缺的一环。然而&#xff0c;用户在使用代理IP时经常会遇到一个问题——延迟。 那我们要如何解决这个问题呢&#xff1f; 这需要从代理IP的原理说…

第七章 正则表达式

目录 1.1. 概念&#xff1a; 1.2. 基本正则表达式 1.2.1. 常见元字符 1.2.2. POSIX字符类 1.2.3. 示例 1.3. 扩展正则表达式 1.3.1. 概念 1.3.2. 示例 1.1. 概念&#xff1a; 在进行程序设计的过程中&#xff0c;用户会不可避免地遇到处理某些文本的情况。有的时候&am…

android 15

https://android-developers.googleblog.com/2024/02/first-developer-preview-android15.html android 15的预览版出了&#xff0c;这个版本的发布计划大概是这样的&#xff08;大约是今年8月发布最终版本&#xff09; https://developer.android.com/about/versions/15/over…

Day34 线程Thread

文章目录 1.什么是线程1.1 概念1.2 进程和线程的区别1.3 线程资源 2.函数接口2.1 创建线程 : pthread_create2.2 退出线程: pthread_exit2.3 回收线程资源 1.什么是线程 1.1 概念 线程是一个轻量级的进程&#xff0c;为了提高系统的性能引入线程。 在同一个进程中可以创建的多…

【YOLO v5 小目标改进】SPD-Conv

SPD-Conv 提出背景SPD-Conv YOLO v5 小目标改进定义 SPD-Conv导入SpaceToDepth模块修改 .yaml 文件 提出背景 论文&#xff1a;https://arxiv.org/pdf/2208.03641v1.pdf 代码&#xff1a;https://github.com/labsaint/spd-conv 文章提出一个新的卷积神经网络(CNN)构建块&…

echarts多y轴样式重叠问题

1、主要属性设置 yAxis: [{//y轴1nameTextStyle: {align: "right",padding: 0}},{//y轴2nameTextStyle: {align: "left",padding: 0}},{//y轴3axisLabel: {margin: 50},nameTextStyle: {align: "left",padding: [0, 0, 0, 50]},axisPointer: {l…

二轮充电桩协议商用通讯协议

文章目录 一、基础通信协议框架二、命令的定义各数据单位定义&#xff1a; 三、设备上传3.0.1、设备心跳包&#xff08;01 指令&#xff09;3.0.2、设备注册包&#xff08;20 指令&#xff09;3.0.3、设备获取服务器时间&#xff08;22 指令&#xff09;3.1、设备心跳包&#x…

基于springboot+vue的靓车汽车销售网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

ChatGPT在数据处理中的应用

ChatGPT在数据处理中的应用 今天的这篇文章&#xff0c;让我不断体会AI的强大&#xff0c;愿人类社会在AI的助力下走向更加灿烂辉煌的明天。 扫描下面二维码注册 ​ 数据处理是贯穿整个数据分析过程的关键步骤&#xff0c;主要是对数据进行各种操作&#xff0c;以达到最终的…

【Git】:标签功能

标签功能 一.标签操作二.推送远程标签 标签 tag &#xff0c;可以简单的理解为是对某次commit的⼀个标识&#xff0c;相当于起了⼀个别名。例如&#xff0c;在项⽬发布某个版本的时候&#xff0c;针对最后⼀次commit起⼀个v1.0这样的标签来标识⾥程碑的意义。这有什么⽤呢&…

uniapp微信小程序解决上方刘海屏遮挡

问题 在有刘海屏的手机上&#xff0c;我们的文字和按钮等可能会被遮挡 应该避免这种情况 解决 const SYSTEM_INFO uni.getSystemInfoSync();export const getStatusBarHeight ()> SYSTEM_INFO.statusBarHeight || 15;export const getTitleBarHeight ()>{if(uni.get…

Ubuntu系统本地部署Inis博客结合内网穿透实现远程访问本地站点

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

统计图雷达图绘制方法

统计图雷达图绘制方法 常用的统计图有条形图、柱形图、折线图、曲线图、饼图、环形图、扇形图。 前几类图比较容易绘制&#xff0c;饼图环形图绘制较难。 还有一种雷达图的绘制也较难&#xff0c;今提供雷达图的绘制方法供参考。 本方法采用C语言的最基本功能&#xff1a; &am…

GoLand 相关

goland 下载依赖 go mod tidy&#xff1a;保持依赖整洁 go mod tidy 命令的作用是清理未使用的依赖&#xff0c;并更新 go.mod 以及 go.sum 文件。 go mod tidy 和 go mod vendor 两个命令是维护项目依赖不可或缺的工具。go mod tidy 确保了项目的 go.mod 文件精简且准确&…

精通Django模板(模板语法、继承、融合与Jinja2语法的应用指南)

模板&#xff1a; 基础知识&#xff1a; ​ 在Django框架中&#xff0c;模板是可以帮助开发者快速⽣成呈现给⽤户⻚⾯的⼯具模板的设计⽅式实现了我们MVT中VT的解耦(M: Model, V:View, T:Template)&#xff0c;VT有着N:M的关系&#xff0c;⼀个V可以调⽤任意T&#xff0c;⼀个…

【Git企业实战开发】Git常用开发流操作总结

【Git企业实战开发】Git常用开发流操作总结 大家好 我是寸铁&#x1f44a; 总结了一篇Git常用开发流操作总结的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 现在刚做项目的伙伴&#xff0c;可能你之前学过git&#xff0c;但是一实战发现不熟悉 没关系&#xff0c;看寸铁这篇…

vscode与vue环境配置

一、下载并安装VScode 安装VScode 官网下载 二、配置node.js环境 安装node.js 官网下载 会自动配置环境变量和安装npm包(npm的作用就是对Node.js依赖的包进行管理)&#xff0c;此时可以执行 node -v 和 npm -v 分别查看node和npm的版本号&#xff1a; 配置系统变量 因为在执…

【计算机考研择校】双非跨考推荐院校名单

各个层次计算机考研院校的推荐汇总&#xff1a; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 本人双非科班出身备考408成功上岸&#xff0c;在这里也想给想考408的学弟学妹们一些很中肯的&#xff0c;学习建议。 我是科班水过408的四门课 说实话&am…

C#中的关键字params的用法

C#中有一个关键字params&#xff0c;它相对于一些主要关键字来说&#xff0c;还算是较为低频的&#xff0c;但也会用到。我们可以了解和学习下。 一、定义及约束 params关键字的作用在于可以让方法参数的数目可变。 params的参数类型必须是一维数组。 一旦在方法加入了para…