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,一经查实,立即删除!

相关文章

数据库开发工具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 、 结合源代码分析用 …

LinkedBlockingQueue原理探究

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

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

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

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

随着人们的生活水平的提升&#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…

Java程序员面试-场景篇

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

HttpServletRequest setHeader

HttpServletRequest setHeader

Python——欢迎来到吱昂张游乐园

欢迎来到吱昂张游乐园&#xff01;&#xff01;&#xff01; 凡是身高小于120或者您的vip等级大于三级的皆可免费游玩。 那我们接下来就来设计一下以上的规则叭 print("欢迎来到吱昂张游乐园") if int(input("输入您的身高&#xff1a;"))>120:print…

什么是全链路压测?

随着互联网技术的发展和普及&#xff0c;越来越多的互联网公司开始重视性能压测&#xff0c;并将其纳入软件开发和测试的流程中。 阿里巴巴在2014 年双11 大促活动保障背景下提出了全链路压测技术&#xff0c;能更好的保障系统可用性和稳定性。 什么是全链路压测&#xff1f;…

中兴服务器R5300 G5算力强劲,有力支撑企业数字化转型

去年&#xff0c;可以说是AIGC大模型全面崛起的一年&#xff0c;反映出人类算力技术的突出发展成果&#xff0c;也带动全球算力规模的进一步扩大。伴随着各行各业都在投身数字化转型&#xff0c;未来人们对于算力的需求更为庞大&#xff0c;因此需要性能更优的服务器来进行支撑…

用PDETool计算磁场

学习FEM和磁场&#xff0c;Matlab中的PDETool可以直观的展示数学的结果。 在PDETool中计算磁场的步骤如下&#xff1a; 1.启动matalb&#xff0c;输入命令pdetool 2.画三个矩形 3.在工具栏的下拉列表中选Magnetostatics 4.设置区域电密 在PDE菜单中&#xff0c;选择PDEmode…