C++qt-信号-信号槽

1、概念

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

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

  • 通信的对象必须都是从QObject类中派生出来的。
  • 类中要有Q_OBJECT宏。
  • 2、函数原型

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

【例子】:如果金龙考试考了100分,新宇请金龙吃饭。

// 参数1:const QObject * sender 发射者,表示因发起对象
// 参数2:const char * signal信号函数,表示因的发起动作,使用SIGNAL()包裹。
// 参数3:const QObject * receiver 接收者,表示果的发起对象
// 参数4:const char * method 槽函数,表示果发起的动作,请吃饭,SLOT()包裹。
QObject:: connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)[static]

3、实现

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

  • 自带信号 -> 自带槽
  • 自带信号 -> 自定义槽
  • 自定义信号

3.1 自带信号->自带槽

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

查找函数 F1F1 查找手册

查找函数:在对应的QPushButton Class基类继承自(QAbstractButton)类,查找自带槽(Public Slots),找到对应槽函数(click),

// 按钮按下后时发射的信号
void QAbstractButton:: clicked(bool checked = false)[signal]

查询函数:在对应的Widget基类查找自带槽(Public Slots),找到对应槽函数(close),

// 关闭 槽函数
bool QWidget:: close()

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QDebug>
#include <QPushButton>


class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    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);
    //but 发起者、SIGNAL()包裹发起动作:点击、this 接收者、SLOT(close()) 接收结果 close关闭窗口
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}
Dialog::~Dialog()
{
    // C++内存回收
    delete btn;
}

3.2 自带信号->自定义槽

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

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

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

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
// 添加头文件QDialog对话框基类,Qt自带类型通常使用Q开头
#include <QDialog>
#include <QDebug>
#include <QPushButton>
// 自定义对话框类
// 继承于QDialog类
class Dialog : public QDialog
{
    // 是一个宏是必要条件:一个标准,有这个宏才可以用connect链接
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);    // 构造函数
    ~Dialog();      // 析构函数
    QPushButton *btn;   // 成员变量
    //声明自定义槽函数
private slots://最小权限法则,能使用私有权限就是用私有(固定写法:表示声明的是一个槽函数,connect连接时才能找到该槽函数)
    void mySlot();//小驼峰命名:第一个单词首字母小写,其他大写
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
// 构造函数定义
// parent 参数
Dialog::Dialog(QWidget *parent): QDialog(parent)   // 透传构造
{
    //设置窗口宽高
    resize(500,500);
    btn = new QPushButton("移动",this);
    //设置按钮位置
    btn->move(200,200);
    //but 发起者、SIGNAL(clicked()) 发起动作:点击、this 接收者、SLOT(close()) 接收结果 close关闭窗口
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}
// 析构函数类外定义
Dialog::~Dialog()
{
    // C++内存回收
    delete btn;
}
//槽函数定义
void Dialog::mySlot()
{
    //先获取当前窗口坐标
    int x = this->x();//坐标函数返回值就是坐标值
    int y = this->y();
    //移动坐标位置,每次获取的都是最新的坐标位置,所以不需要赋值
    move(x+10,y+10);
    //输出当前坐标位置
    qDebug()<<x+10<<y+10;
}

3.3 自定义信号

emit关键字发射。

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

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

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

3.1 节的信号连接方式

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

上图中表示信号槽连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    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)
{
    resize(500,500);
    btn = new QPushButton("杀鸡用牛刀",this);
    btn->move(200,200);
    //第一次信号槽链接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    //第二次信号槽链接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}
Dialog::~Dialog()
{
    //释放类对象堆空间
    delete btn;
}
void Dialog::mySlot()
{
    //发射信号
    emit mySignal();
}

步骤:自定义信号无法调用,只能发射信号,因此在头函数内声明自定义信号和自定义槽函数,在自定义槽函数内发射该自定义信号,并调用相关槽函数。(声明自定义槽函数和自定义信号,需要connect连接多次)

4、信号槽传参

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

// QPushButton的文字属性为text:QString,可以使用setText更改按钮文字
// 参数:更新的文字
void	setText(const QString & text)

正常解法(非信号槽传参):

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;
    //自定义槽函数声明
private slots:
    void mySlot();
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    //btn初始化 初始数据为”0“
    btn = new QPushButton("0",this);
    btn->move(200,200);
    //connect 连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}
Dialog::~Dialog()
{
    delete btn;
}
void Dialog::mySlot()
{
    //静态局部变量
    static int count = 0;
    count++;
    //类型转换 int-> QString,整形转字符型,number(形参):形参:要转换的数据
    QString text = QString::number(count);
    btn->setText(text);//更改按钮文字
}

信号槽传参法:

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

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;
    //自定义槽函数声明
private slots:
    void mySlot();
    void mySlot2(int);//有参自定义槽函数
signals:
    void mySignal(int);//有参自定义信号函数
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn = new QPushButton("0",this);
    btn->move(200,200);
    //connect 连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(int)),this,SLOT(mySlot2(int)));
}
Dialog::~Dialog()
{
    delete btn;
}
//自定义信号槽初始化
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);
}

需要注意的是:

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

5、对应关系

5.1 一对多

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

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug>
#include <QPushButton>
class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn0;
    QPushButton *btn1;
    QPushButton *btn2;
private slots:
    void mySlot0();
    void mySlot1();
    void mySlot2();
};

#endif // DIALOG_H

dialog.cpp

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

在头文件内声明的函数,可以以下操作在主函数内自定添加定义

5.2 多对一

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

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
#include <QDebug>
class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    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(300,300);

    // 多对一连接
    connect(btn1,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
    connect(btn2,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}
Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}
void Dialog::btnClickedSlot()
{
    // 通过sender函数获取发射者对象
    if(sender() == btn1)
    {
        qDebug() << "A" ;
    }
    else if(sender() == btn2)
    {
        qDebug() << "B" ;
    }
    else
    {
        qDebug() << "对象错误" ;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iOS 应用上架指南:资料填写及提交审核

摘要 本文提供了iOS新站上架资料填写及提交审核的详细指南&#xff0c;包括创建应用、资料填写-综合、资料填写-IOS App和提交审核等步骤。通过本指南&#xff0c;您将了解到如何填写正确的资料&#xff0c;并顺利通过苹果公司的审核。 引言 在开发iOS应用后&#xff0c;将其…

视频监控系统EasyCVR如何通过调用API接口查询和下载设备录像?

智慧安防平台EasyCVR是基于各种IP流媒体协议传输的视频汇聚和融合管理平台。视频流媒体服务器EasyCVR采用了开放式的网络结构&#xff0c;支持高清视频的接入和传输、分发&#xff0c;平台提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联…

oracle基本用户管理和权限分配

1.用户与模式的关系&#xff0c;一一对应的关系 2.创建与管理用户 2.1创建用户语法 CREATE user wdf IDENTIFIED by tiger--创建用户wdf,密码tiger DEFAULT tablespace users--用户的默认表空间 quota 10M on users;--在表空间的占用最大空间 注意&#xff1a;用户创建以后…

基于TableAgent实现IT职位招聘数据分析—以传统机器学习与TableAgent 数据分析方式相对比以凸显TableAgent 特性

目录 &#x1f680;一. TableAgent—新AI时代的数据分析智能体 &#x1f50e;1.1 基于DataCanvas Alaya九章元识大模型 &#x1f50e;1.2 TableAgent的亮点 &#x1f680;二. 使用TableAgent分析数据与传统机器学习分析数据对比 &#x1f50e;2.1 项目背景 &#x1f50e;2.2 数…

统信UOS命令行设置未签名软件安装权限

原文链接&#xff1a;统信UOS命令行设置未签名软件安装权限 hello&#xff0c;大家好啊&#xff01;今天我要给大家介绍的是在统信UOS操作系统上通过命令行设置安全中心应用安装权限的方法。在某些情况下&#xff0c;用户可能需要安装未经官方签名的软件包。虽然这可以提供更多…

在python里面探索web框架

一、常识性知识 python Web框架三巨头&#xff1a;Flask&#xff08;简单易学&#xff09;、Django(复杂庞大)、FastAPI 1. Django&#xff1a;Django是一个高级的Web框架&#xff0c;它提供了强大的功能和工具&#xff0c;用于快速开发复杂的Web应用程序。 2. Flask&#xff…

2024 CSRankings全球计算机科学排名发布!清华AI第一,哈工大NLP第一

大家好我是二狗。 这两天全球计算机科学排名 CSRankings 2024发布啦&#xff01; 下面二狗就带大家来看一下最新的排名情况。 清华、北大、上海交大AI领域霸榜前三 在AI板块&#xff0c;主要有人工智能、计算机视觉、机器学习、自然语言处理、网络&信息检索5个细分领域。…

【obj To 3DTiles 格式转换】 可以自定义经纬高、属性表等参数 (一)

目录 0 引言1 3DTiles数据2 objTo3DTiles2.1 工具的安装2.1.1 拓展&#xff1a;Node.js 和 npm 2.2 工具的使用2.2.1 输出成瓦片数据2.2.2 输出带有坐标参数的瓦片数据 3 查看3DTiles数据 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;Cesiumfor…

玄子Share-云计算入门指南

玄子Share-云计算入门指南 一、Windows 键盘字符输入 1. 单键位 直接通过键盘输入即可 2. 双键位 功能键&#xff0c;键盘上显示为两排符号&#xff0c;普通输入模式默认输入下排字符&#xff0c;键盘按下Shift&#xff08;转换&#xff09;键&#xff0c;上档键&#xff0…

8 单链表---带表头节点

上节课所学的顺序表的缺点 顺序表的最大问题&#xff1a;插入和删除时需要移动大量元素 链式存储的定义 链式存储的逻辑结构 链表中的基本概念&#xff1a; 注意&#xff1a;表头节点并不属于数据元素 单链表图示&#xff1a; 把3个需要的结构体定义出来&#xff1a; typdef …

矩阵中的最长递增路径

题目链接 矩阵中的最长递增路径 题目描述 注意点 不能 在 对角线 方向上移动或移动到 边界外&#xff08;即不允许环绕&#xff09; 解答思路 因为最长递增路径一定是连续的&#xff0c;所以想到使用深度优先遍历来做。如果只使用深度优先遍历会导致超时&#xff08;同一个…

IP风险画像:源头防范网络攻击的全面策略

在当今数字化的时代&#xff0c;网络攻击呈现多样化和复杂化的趋势&#xff0c;为了确保网络的安全&#xff0c;制定全面的IP风险画像并从源头防范网络攻击是至关重要的。ip数据云将探讨如何通过建立IP风险画像来识别和应对潜在的威胁&#xff0c;从而实现更加安全可靠的网络环…

基于Hologres+Flink的曹操出行实时数仓建设作者:林震|曹操出行实时计算负责人

作者&#xff1a;林震&#xff5c;曹操出行实时计算负责人 曹操出行业务背景介绍 曹操出行创立于2015年5月21日&#xff0c;是吉利控股集团布局“新能源汽车共享生态”的战略性投资业务&#xff0c;以“科技重塑绿色共享出行”为使命&#xff0c;将全球领先的互联网、车联网、…

docker镜像的生成过程

镜像的生成过程 Docker镜像的构建过程&#xff0c;大量应用了镜像间的父子关系。即下层镜像是作为上层镜像的父镜像出现的&#xff0c;下层镜像是作为上层镜像的输入出现。上层镜像是在下层镜像的基础之上变化而来。 FROM centos:7 FROM指令是Dockerfile中唯一不可缺少的命令&a…

2023年12月青少年机器人技术等级考试(四级)理论综合试卷

2023年12月青少年机器人技术等级考试&#xff08;四级&#xff09;理论综合试卷 题目总数&#xff1a;30 总分数&#xff1a;100 单选题 第 1 题 单选题 Arduino UNO/Nano主控板&#xff0c;当数字引脚输出信号为高电平时&#xff0c;对应的电压是 &#xff1f;&…

Replace()函数实例讲解——vba

Replace函数 描述 返回一个字符串&#xff0c;该字符串中指定的子字符串已被替换成另一子字符串&#xff0c;并且替换发生的次数也是指定的。 语法 Replace(expression, find, replace[, start[, count[, compare]]]) Replace函数语法有如下命名参数&#xff1a; …

nginx+keepalived双主模式双主热备

目录 一、双主模式原理 1. nginxkeepalived主备模式缺点 2. 主备模式和双主模式的区别 二、配置文件 1. nginx01的keepalived.conf 2. nginx02的keepalived.conf 3. 检测nginx存活脚本文件nginx_check.sh 三、测试准备 1. 启动nginx01、nginx02 2. 启动keepalived 3. 查看网卡信…

Linux——firewalld防火墙(一)

一、Linux防火墙基础 Linux 的防火墙体系主要工作在网络层.针对TCP/P数据包实时过滤和限制.属于典型的包过滤防火墙&#xff08;或称为网络层防火墙)。Linux系统的防火墙体系基于内核编码实现&#xff0e;具有非常稳定的性能和高效率,也因此获得广泛的应用.在CentOS 7系统中几种…

D42D43D44|买卖股票的最佳时机

121.买卖股票的最佳时机 初始思路&#xff1a; 暴力解法&#xff0c;两个for循环。 class Solution {public int maxProfit(int[] prices) {int res Integer.MIN_VALUE;for(int i 0;i<prices.length;i){for(int j i1;j<prices.length;j){res Math.max(res,prices[…

Python画国旗

前言 今天&#xff0c;我们来用turtle库来绘制国旗 一、美国国旗 国旗的形状是长方形;国旗的长宽之比为19:10&#xff0c;美国国旗由红、白、蓝三色组成;画面格局由两部分组成&#xff0c;旗的左上方蓝底上排列着50颗白色的星&#xff0c;6颗一排与5颗一排相间排列&#xff…