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_OBJECTpublic: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_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)
{
    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() << "对象错误" ;}
}

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

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

相关文章

3.C语言:函数与程序结构

Function 函数定义与声明外部变量与作用域头文件静态变量static寄存器变量程序块结构&#xff08;作用域&#xff09;初始化递归C预处理器 函数定义与声明 函数定义形式&#xff1a; 返回值类型函数明(参数声明表) {声明和语句 }函数定义中的各构成部分都可以省略。 不执行任…

数据库开发工具Navicat Premium 15 mac软件特色

Navicat Premium 15 mac版是一款数据库开发工具&#xff0c;Navicat Premium 15 Mac版可以让你以单一程序同時连接到 MySQL、MariaDB、SQL Server、SQLite、Oracle 和 PostgreSQL 数据库。 Navicat Premium mac软件特色 无缝数据迁移 数据传输&#xff0c;数据同步和结构同步…

婚恋/社交娱乐/同城相亲/红娘相亲交友软件开发小程序

需求分析&#xff1a;首先明确小程序的目标、功能和用户需求。确定小程序的主要功能&#xff0c;例如用户注册、登录、个人资料编辑、浏览其他用户资料、发送消息等。 技术选型&#xff1a;选择适合的开发框架和技术工具。在小程序开发中&#xff0c;可以使用微信小程序原生开…

电脑开启虚拟化如何查看自己的主机主板型号

问题描述 在使用virtualbox、vmware安装虚拟机的时候&#xff0c;需要本机电脑能够支持虚拟化。 但是不同厂家的主机&#xff08;主板&#xff09;幸好并不一致&#xff0c;所以需要先了解自己的电脑主板型号 操作方法 1、win r 键打开运行窗口&#xff0c;输入cmd并确定打开…

3D PDF查看器HOOPS Publish助力Smartscape拓展日本AEC市场!

​ 公司&#xff1a;Smartscape Co., Ltd. 行业&#xff1a;建筑、工程和施工(AEC) 软件&#xff1a;适用于AEC行业的3D PDF工具 软件开发工具包&#xff1a;Hoops Publish HOOPS_3D软件开发工具_HOOPS中文网慧都科技是HOOPS全套产品中国地区指定授权经销商&#xff0c;提供3D…

流畅芯视界 | 极海APM32F411 OLED驱动方案

随着技术的不断革新与进步&#xff0c;OLED显示技术以其在显示画质、设备厚度和能耗方面的显著表现&#xff0c;正在改变着人们的视觉体验。相较于传统液晶显示技术&#xff0c;OLED凭借更好的色彩表现力、更高对比度、以及能够实现更加轻薄的产品设计而日益受到消费者的青睐。…

zabbix部署

zabbix部署 部署zabbix服务被监测主机部署zabbix-agent2 使用版本 组件版本centos7.9zabbix5.0php7.2.24MariaDB5.5.68 部署zabbix服务 关闭防火墙和selinux [rootnode ~]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemonLoaded: …

Vue-8、Vue事件处理

1、点击事件 <!DOCTYPE html> <html lang"en" xmlns:v-model"http://www.w3.org/1999/xhtml" xmlns:v-bind"http://www.w3.org/1999/xhtml"xmlns:v-on"http://www.w3.org/1999/xhtml"> <head><meta charset&quo…

0108作业

#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->setWindowTitle("腾讯会议");this->resize(470,800);//设置界面大小this->setFixedSize(470,800);//锁定界面大小this->setStyleSheet("background-color:w…

信息系统安全——基于 AFL 的模糊测试

实验 3 基于 AFL 的模糊测试 3.1 实验名称 《基于 AFL 的模糊测试》 3.2 实验目 1 、熟悉模糊测试方法 2 、熟悉模糊测试工具 AFL 的使用 3.3 实验步骤及内容 1 、 安装 AFL 2 、 任意选择一个有源代码的样本 这里采用教材上一个包含栈溢出漏洞的样本。 3 、 结合源代码分析用 …

2024.1.8力扣每日一题——回旋镖的数量

2024.1.8 题目来源我的题解方法一 双层哈希表方法二 哈希表优化版 题目来源 力扣每日一题&#xff1b;题序&#xff1a;447 我的题解 方法一 双层哈希表 构造如下的哈希表&#xff1a;{节点i&#xff1a;{距离1&#xff1a;数量&#xff0c;…距离n&#xff1a;数量}} 相当于…

LinkedBlockingQueue原理探究

类图结构 同样首先看一下LinkedBlockingQueue的类图结构&#xff0c;以便从全局对LinkedBlockingQueue有个直观的了解。 由类图可以看到&#xff0c;LinkedBlockingQueue也是使用单向链表实现的&#xff0c;其也有两个Node,分别用来存放首、尾节点&#xff0c;并且还有一个初始…

Shell脚本入门实战:探索自动化任务与实用场景

引言 Shell脚本作为一种强大的自动化工具&#xff0c;在现代操作系统中具有广泛的应用。无论是简单的文件操作&#xff0c;还是复杂的系统管理&#xff0c;Shell脚本都能提供高效、快速的解决方案。在本文中&#xff0c;我们将探索Shell脚本的基础知识&#xff0c;并通过实战场…

x-cmd pkg | rg - 文本搜索工具,grep 命令的现代化替代品

目录 简介首次用户功能特点竞品和相关作品进一步阅读 简介 rg&#xff08;ripgrep&#xff09; 是一个逐行方式进行&#xff08; line-oriented &#xff09;的文本搜索工具&#xff0c;能够递归搜索目录中的文件内容。默认情况下&#xff0c;rg 将遵守 .gitignore 文件规则自…

偷偷读个中国社科院与新加坡新跃社科联合培养博士惊艳你们

近期&#xff0c;华尔街量化圈应届生的年薪超200万刷屏&#xff01;国内量化的人才市场又是怎样的呢&#xff1f;据记者调查&#xff0c;当前在应届生的招聘上主要以顶尖高校的博士为主&#xff0c;年薪百万起步&#xff0c;同时为实习人才提供每日1500元的实习津贴。一般情况下…

内衣洗衣机哪些品牌质量好实惠?五款好用的迷你洗衣机

随着人们的生活水平的提升&#xff0c;越来越多小伙伴来开始追求更高的生活水平&#xff0c;一些智能化的小家电就被发明出来&#xff0c;而且内衣洗衣机是其中一个。现在通过内衣裤感染到细菌真的是越来越多&#xff0c;所以我们对内衣裤的清洗频次会高于普通衣服&#xff0c;…

视频号小店和抖音小店相比,新手做哪个比较好?

我是电商珠珠 抖音小店在19年被抖音所发展&#xff0c;在这过程中&#xff0c;抖音小店通过自身的不断完善&#xff0c;从兴趣电商到全域兴趣电商模式&#xff0c;从直播电商到商城的出现&#xff0c;凭借着门槛低流量高的优势&#xff0c;让很多商家尝到了红利。 尤其是在20…

大创项目推荐 深度学习实现行人重识别 - python opencv yolo Reid

文章目录 0 前言1 课题背景2 效果展示3 行人检测4 行人重识别5 其他工具6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的行人重识别算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

Cookie Session和过滤器Filter

会话&#xff1a;用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可以包含多次请求和响应。 会话跟踪&#xff1a;一种维护浏览器状态的方法&#xff0c;服务器需要识别多次请求是否来自…

Java程序员面试-场景篇

前言 裁员增效潮滚滚而来&#xff0c;特总结一些实际场景方案的面试题&#xff0c;希望对大家找工作有一些帮助。 注册中心 题目&#xff1a; 有三台机器&#xff0c;分别部署了微服务A、微服务B、注册中心&#xff0c;其中A和B都有服务接口提供并正常注册到了注册中心&…