Qt_day3_信号槽

news2024/12/25 12:45:45

目录

信号槽

1. 概念

2. 函数原型

3. 连接方式

3.1 自带信号 → 自带槽

3.2 自带信号 → 自定义槽

3.3 自定义信号

4. 信号槽传参

5. 对应关系

5.1 一对多

5.2 多对一


信号槽

1. 概念

    之前的程序界面只能看,不能交互,信号槽可以让界面进行人机交互。

    信号槽是Qt在C++基础上新增的特性,类似于其他编程中的回调机制,其目的是实现对象之间的通信。

使用信号槽需要具备两个先决条件:

  • 通信的对象必须继承自QObject

QObject是Qt所有对象的基类,内部规定了Qt最基础的对象特性。

  • 类中要包含Q_OBJECT宏

2. 函数原型

信号槽的建立是通过connect函数实现的。

// 信号槽连接函数
// 参数1:发射者,因发起的对象n.
// 参数2:信号函数,因的动作v.,需要使用SIGNAL()包裹函数名称
// 参数3:接收者,果执行的对象n.
// 参数4:槽函数,果的动作v.,需要使用SLOT()包裹函数名称
QObject::​connect(const QObject * sender, 
				    const char * signal, 
				    const QObject * receiver, 
				    const char * slot)                [static]

    信号函数一定来自于发射者,槽函数一定来自于接收者。信号槽的连接必须在发射者对象和接收者对象创建完成后进行,如果成功连接后,发射者或接收者对象销毁了,连接断开。

    信号槽的连接也可以程序员手动断开,只需要把connect函数改为disconnect即可,参数保持不变。

3. 连接方式

为了讲课,按照难易程度分为三种连接方式:

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

3.1 自带信号 → 自带槽

    这种连接方式是最简单的连接方式,因为信号函数和槽函数都是Qt内置的,程序员只需要找到连接的四个参数,直接连接即可。

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

分析:

参数1:发射者——按钮对象

参数2:信号函数——点击

void QAbstractButton::​clicked()                    [signals]

参数3:接收者——窗口对象

参数4:槽函数——关闭

bool QWidget::​close()                            [slot]

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;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("关闭",this);
    btn->move(100,100);
    //  参数1:发射者——按钮对象
    //	参数2:信号函数——点击
    //	参数3:接收者——窗口对象
    //	参数4:槽函数——关闭
    connect(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_OBJECT

public:
    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(400,400);
    btn = new QPushButton("关闭",this);
    btn->move(100,100);
    // 连接信号槽
    connect(btn,SIGNAL(clicked()),
            this,SLOT(mySlot()));
}

void Dialog::mySlot()
{
    // 先获得当前坐标
    int x = this->x();
    int y = this->y();
    // 移动
    move(x+10,y+10);
    // 输出当前窗口位置
    qDebug() << this->x() << this->y();
}

Dialog::~Dialog()
{
    delete btn;
}

3.3 自定义信号

    自定义信号通常用于解决一些对象之间“远距离”通信问题,本节属于强行使用,因此并不是问题最优解,只是为了展示自定义信号的使用方式。

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

先忽略自定义信号,展示正常解法:

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();

private:
    QPushButton* btn;
    int count;

private slots:
    void btnClickedSlot(); // 点击按钮的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0) // 构造初始化列表
{
    resize(400,400);
    btn = new QPushButton("0",this);
    btn->move(200,200);

    connect(btn,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}

void Dialog::btnClickedSlot()
{
    count++;
    // int → QString
    QString text = QString::number(count);
    // 设置到按钮上显示
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

基于上面的解法,强行增加自定义信号发射环节:

     信号函数是一种特殊的函数,只有声明没有定义,声明后可以直接配合emit关键字发射。

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();

private:
    QPushButton* btn;
    int count;

signals:
    void countSignal(); // 自定义信号

private slots:
    void btnClickedSlot(); // 点击按钮的槽函数
    void countSlot(); // 与自定义信号连接的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0) // 构造初始化列表
{
    resize(400,400);
    btn = new QPushButton("0",this);
    btn->move(200,200);

    connect(btn,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
    connect(this,SIGNAL(countSignal()),
            this,SLOT(countSlot()));
}

void Dialog::btnClickedSlot()
{
    count++;
    // 发射自定义信号
    emit countSignal();
}

/**
 * @brief Dialog::countSlot
 * 中转之后更新按钮显示的槽函数
 */
void Dialog::countSlot()
{
    QString text = QString::number(count);
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

4. 信号槽传参

    信号槽可以进行参数传递,信号函数携带参数发射,槽函数可以收到此参数。

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();

private:
    QPushButton* btn;
    int count;

signals:
    void countSignal(int); // 自定义信号

private slots:
    void btnClickedSlot(); // 点击按钮的槽函数
    void countSlot(int); // 与自定义信号连接的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0) // 构造初始化列表
{
    resize(400,400);
    btn = new QPushButton("0",this);
    btn->move(200,200);

    connect(btn,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
    connect(this,SIGNAL(countSignal(int)),
            this,SLOT(countSlot(int)));
}

void Dialog::btnClickedSlot()
{
    count++;
    // 发射自定义信号(携带参数)
    emit countSignal(count);
}

/**
 * @brief Dialog::countSlot
 * count参数是信号函数发来的,不是成员变量
 * 中转之后更新按钮显示的槽函数
 */
void Dialog::countSlot(int count)
{
    QString text = QString::number(count);
    btn->setText(text);
}

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_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn1;
    QPushButton* btn2;

private slots:
    void btnClickedSlot1();
    void btnClickedSlot2();
    void btnClickedSlot3(); // 3 = 1 + 2
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn1 = new QPushButton("一对多", this);
    btn1->move(200,100);
    btn2 = new QPushButton("一对一", this);
    btn2->move(100,200);

    // 一对多
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot1()));
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot2()));
    // 一对一
    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot3()));
}

void Dialog::btnClickedSlot1()
{
    qDebug() << "A";
}

void Dialog::btnClickedSlot2()
{
    qDebug() << "B";
}

void Dialog::btnClickedSlot3()
{
    // 直接把Slot1和Slot2两个函数当做普通的成员函数,
    // 使用this指针调用
    btnClickedSlot1();
    btnClickedSlot2();
}

Dialog::~Dialog()
{
    delete btn1;
}

5.2 多对一

    多对一的连接方式下,槽函数无法区分信号来源,可以在槽函数中调用sender函数获取发射者对象,从而判断信号来源。

// 在槽函数中调用,返回发射者对象
QObject * QObject::​sender() const

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();

private:
    QPushButton* btn1;
    QPushButton* btn2;

private slots:
    void btnsClickedSlot();
};

#endif // DIALOG_H

dialog.cpp
#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn1 = new QPushButton("A",this);
    btn2 = new QPushButton("B",this);
    btn1->move(150,100);
    btn2->move(150,200);

    // 多对一
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnsClickedSlot()));
    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnsClickedSlot()));
}

void Dialog::btnsClickedSlot()
{
    if(btn1 == sender())
    {
        qDebug() << "点击了按钮1";
    }else if(btn2 == sender())
    {
        qDebug() << "点击了按钮2";
    }
    qDebug() << "槽函数触发!";
}

Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}

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

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

相关文章

Elastic 通用分析:提高性能并降低成本

作者&#xff1a;来自 Elastic Luca Wintergerst•Tim Rhsen 在这篇博客中&#xff0c;我们将介绍我们的一位工程师的一项发现如何帮助我们在 QA 环境中节省数千美元的成本&#xff0c;并且一旦我们将这一变化部署到生产中&#xff0c;还可以节省更多的成本。 在当今的云服务和…

【WRF理论第十一期】检查WPS输出:geogrid和metgrid 的输出nc数据+ungrib输出WPS格式

【WRF理论第十一期】检查WPS输出&#xff1a;geogrid和metgrid输出nc数据ungrib输出WPS格式 检查WPS输出WPS 输出检查的重要性使用 NetCDF 格式查看 geogrid 和 metgrid 的输出检查和可视化数据的工具 ungrib 输出数据的格式使用 plotfmt 工具查看 ungrib 输出 参考 上一篇博客…

万字长文解读深度学习——卷积神经网络CNN

推荐阅读&#xff1a; 卷积神经网络&#xff08;CNN&#xff09;详细介绍及其原理详解 CNN笔记&#xff1a;通俗理解卷积神经网络 文章目录 &#x1f33a;深度学习面试八股汇总&#x1f33a;主要组件输入层卷积层 (Convolutional Layer)批归一化层&#xff08;Batch Normalizat…

Redis生产问题(缓存穿透、击穿、雪崩)——针对实习面试

目录 Redis生产问题什么是缓存穿透&#xff1f;如何解决缓存穿透&#xff1f;什么是缓存击穿&#xff1f;如何解决缓存击穿&#xff1f;缓存穿透和缓存击穿有什么区别&#xff1f;什么是缓存雪崩&#xff1f;如何解决缓存雪崩&#xff1f; Redis生产问题 什么是缓存穿透&#x…

19、centos7优化

优化条目&#xff1a; 优化条目&#xff1a; 1.sudo管理用户授权 &#xff08;不用root管理,以普通用户的名义通过sudo提权&#xff09; 2.更改默认的远程连接SSH服务端口,禁止root用户远程连接,&#xff08;提前建立普通用户&#xff09;&#xff08;甚至更改为只监听内网IP…

河北省内首台心磁图仪正式落户河北梅奥心血管病医院

河北省内首台心磁图仪正式落户河北梅奥心血管病医院。 2024年11月9日&#xff0c;河北梅奥心血管病医院迎来了一场激动人心的历史时刻——河北省首台心磁图仪启用仪式在医院内隆重举行&#xff0c;标志着这一顶尖医疗设备正式入驻&#xff0c;为医院心脏影像诊断技术开启了全新…

【C语言刷力扣】283.移动零

题目&#xff1a; 解题思路&#xff1a; 将不为 0 的元素依次放在数组前面&#xff0c;再在数组末尾补上 0。 时间复杂度&#xff1a; 空间复杂度&#xff1a; void moveZeroes(int* nums, int numsSize) {int i 0, j 0;for (; i < numsSize; i) {if (nums[i]) {nums…

网络初阶——应用层:HTTPS 协议

一、HTTPS & HTTP 的区别 从协议的名字来看&#xff0c;HTTP 比 HTTPS 少了一个 S。而这个 “S”&#xff0c;其实可以理解成 “Safe”&#xff0c;所以不难看出&#xff0c;其实 HTTPS 就是 HTTP 的安全版。就是为了保证客户端 cookie 的传输安全的。 二、相关概念 1、明…

怎么禁止Ubuntu自动更新升级

怎么禁止Ubuntu自动更新升级 笔者在做MIT 6.S081的时候发现他给我的qemu自动更新了又卡住了&#xff0c;故关闭了自动更新 文章目录 怎么禁止Ubuntu自动更新升级一、图形化修改二、基于命令行修改配置文件的方法 一、图形化修改 1.打开设置->软件和更新->更新 2.选择自…

Spring Boot框架:构建符合工程认证的计算机课程

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

机器学习—选择激活函数

可以为神经网络中的不同神经元选择激活函数&#xff0c;我们将从如何为输出层选择它的一些指导开始&#xff0c;事实证明&#xff0c;取决于目标标签或地面真相标签y是什么&#xff0c;对于输出层的激活函数&#xff0c;将有一个相当自然的选择&#xff0c;然后看看激活函数的选…

【学习记录】使用CARLA录制双目摄像头SLAM数据

一、数据录制 数据录制的部分参考了网上的部分代码&#xff0c;代码本身并不复杂&#xff0c;基本都是简单的CARLA语法&#xff0c;关键的一点在于&#xff0c;CARLA内部本身并没有预设的双目摄像头&#xff0c;需要我们添加两个朝向相同的摄像头来组成双目系统&#xff0c;这…

[论文粗读][REALM: Retrieval-Augmented Language Model Pre-Training

引言 今天带来一篇检索增强语言模型预训练论文笔记——REALM: Retrieval-Augmented Language Model Pre-Training。这篇论文是在RAG论文出现之前发表的。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 语言模型预训练…

【人工智能】ChatGPT多模型感知态识别

目录 ChatGPT辅助细化知识增强&#xff01;一、研究背景二、模型结构和代码任务流程一&#xff1a;启发式生成 三、数据集介绍三、性能展示实现过程运行过程训练过程 ChatGPT辅助细化知识增强&#xff01; 多模态命名实体识别&#xff08;MNER&#xff09;最近引起了广泛关注。…

【黑马点评debug日记】

q1:登录无session跳转主页 p30&#xff0c;页面登录后返回&#xff0c;然后点击我的&#xff0c;需要重新设置&#xff0c;拦截器都没有问题。 参考&#xff1a; redis 黑马点评p30 login没有正常跳转&#xff0c;修改前端代码后还是一直跳转主界面_黑马点评登录后跳转到主页…

地面远阴影对光伏电站的影响

影响因素 1、太阳高度角和方位角 太阳高度角是指太阳光的入射方向和地平面之间的夹角。太阳高度角随时间、季节和地理位置的变化而变化。 方位角是指太阳光线在水平面上的投影与正南方向的夹角。方位角也随时间和地理位置的变化而变化。 可以通过天文公式或者专业的太阳位置…

消息队列高级

目录 消息可靠性 生产者消息确认 第一步&#xff1a;修改application.yml配置文件信息 第二步&#xff1a;定义发送者确认confirm回调方法 第三步&#xff1a;创建消息发送者回执return回调方法&#xff08;确保消息从交换机到消息队列&#xff09; 总结&#xff1a; 消息持…

宏观经济学笔记

【拯救者】宏观经济学速成 国民生产总值GNP: GNP 衡量一国(地区)成员在一定时期内运用生产要素所生产的全部最终产品和服务的市场价值。凡是本国国民所 创造的收入&#xff0c;不管生产要素是否在国内&#xff0c;都计入本国GNP中。 GDP本国居民在本国创造的价值外国居民在本国…

ONLYOFFICE 8.2测评:功能增强与体验优化,打造高效办公新体验

引言 随着数字化办公需求的不断增长&#xff0c;在线办公软件市场竞争愈加激烈。在众多办公软件中&#xff0c;ONLYOFFICE 无疑是一个颇具特色的选择。它不仅支持文档、表格和演示文稿的在线编辑&#xff0c;还通过开放的接口与强大的协作功能&#xff0c;吸引了众多企业和个人…

独显装完ubuntu后启动黑屏显示/dev/sda:clean files blocks的解决方案

解决方案如下&#xff1a; 选中Ubuntu按E键 在编辑界面倒数第2行的linux那行&#xff08;后面有quiet splash选项&#xff09;的最后添加nomodeset 然后按F10保存重启 然后管理员权限打开/etc/modprobe.d/blacklist.conf&#xff0c;在文件末尾添加&#xff1a; blacklist…