Qt之信号和槽的机制

news/2024/7/23 23:20:01 标签: qt, 开发语言, 后端

前言       

        在 C++ 中,对象与对象之间产生联系要通过调用成员函数的方式。但是在 Qt中,Qt提供了一种新的对象间的通信方式,即信号和槽机制。在GUI编程中,通常希望一个窗口部件的一个状态的变化会被另一个窗口部件知道,为了实现这种效果且取代老式的回调函数,信号和槽机制应运而生,Qt通过 QObject 提供信号和槽的功能。
        信号和槽的核心原理很简单,当某个事件发生之后,如按钮检测到自己被单击了一下,它就会广播出一个信号。如果有对象对这个信号感兴趣,就使用连接函数,将想要处理的信号和自己的一个函数(称为槽函数)进行绑定并处理这个信号。也就是说,当信号被发出时,与之连接的槽即函数会自动被回调。


信号和槽的使用 

        槽的本质就是类的成员函数,其参数可以是任意类型,可以是虚函数,可以被重载。槽通常和信号连接在一起,当信号被发出时,与这个信号连接的槽函数就会被调用,其语法如下。

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

具体参数如下:

  • sender:发出信号的对象。
  • signal:发送对象发出的信号。
  • receiver:接收信号的对象。
  • slot:接收对象在接收到信号之后所需要调用的函数。

        参数中的 sender 就是指向发送信号的对象的指针,receiver 是指向包含槽函数的对象的指针。signal是被发送的信号,slot是接收信号后调用的槽函数,均为不带参数的函数名。SIGNAL()和SLOT()会将其参数转换为字符串,即将函数名转换为字符串,将这个字符串传入 connect()中。

信号和槽的连接比较随意,一个信号可以连接多个槽。
connect(sender, SlGNAL(sianal), receiverA, SLOT(slotA));
connect(sender, SlGNAL(signal), receiverB, SLOT(slotB));

也可以多个信号连接同一个槽。
connect(senderA, SIGNAL(signalA), receiver, SLOT(slot));
connect(senderB, SlGNAL(signalB), receiver, SLOT(slot));

一个信号还可以连接另外一个信号。
connect(sender, SIGNAL(signalA), receiver, SlGNAL(signalB));

当 sender对象发送信号给signalA时,触发receiver对象发送信号给signalB。同时,信号和槽之间的连接可以被移除。
disconnect(sender, SlGNAL(signal),receiver, SLOT(slot));

 Qt 信号和槽机制的优缺点如下:

  • Ot的信号和槽机制的引用可减少程序员编写的代码量。
  • Qt的信号可以对应多个槽(它们的调用顺序随机),也可以多个槽映射一个信号
  • Qt的信号和槽的建立与解除绑定十分自由。
  • 信号和槽同真正的回调函数比起来,时间的耗损还是很大的,在嵌入式实时系统中应当慎用。
  • 信号和槽的参数限定很多,如不能携带模板类参数、不能出现宏定义等。

 用一个例子来解释一下信号和槽的机制:

 新建一个基类 QWidget的 Qt 图形应用项目。

 在widgt.h文件中:

#ifndef WIDGT_H
#define WIDGT_H
#include<QPushButton>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class widgt; }
QT_END_NAMESPACE
class widgt : public QWidget
{
    Q_OBJECT//只有继承了QObject类的类,才具有信号和槽;
            //宏QOBJECT是任何实现信号、槽或属性的强制性要求
public:
    widgt(QWidget *parent = nullptr);
    ~widgt();
private:
    Ui::widgt *ui;
    QPushButton button;
};
#endif // WIDGT_H

在widgt.cpp文件中:

#include "widgt.h"
#include "ui_widgt.h"
widgt::widgt(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::widgt)
{
    this->resize(200,200);//修改默认的窗口尺寸
    button.setParent(this);// 绑定窗口和按钮
    button.setText("关闭窗口");// 按钮框中文本
    button.move(48,64);// 定义按钮的位置,以左上角为原点,px 为单位
    connect(&button,&QPushButton::pressed,this,&widgt::close);
}
widgt::~widgt()
{
    delete ui;
}

在main.cpp文件中:

#include "widgt.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    widgt w;
    w.show();
    return a.exec();
}

        在这些代码中,button是信号的发送方;信号为QPushButton基类定义的pressed信号;信号接收方为 widgt w,即在构造函数中写为 this;槽函数为基类QWidget定义的 close()函数。这样,在单击“close”按钮时,该按钮 button会发送一个pressed信号,pressed信号会触发w中继承的 close()函数,实现结束程序的功能。 


自定义信号和槽函数

         connect()函数可用来连接系统提供的信号和槽。但是,Qt的信号和槽机制并不是仅能使用系统提供的那部分,程序员也可设计自己的信号和槽。

        首先,创建一个基于基类 QWidget的 Qt图形应用项目,添加一个新的类,类名为“Widget”继承于 Qt 的基类 QWidget。

 在widgt.h文件中:

#ifndef WIDGET_H
#define WIDGET_H
#include <QLabel>
#include <QPushButton>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    void MySlot();//定义
    ~Widget();
private:
    Ui::Widget *ui;
    QPushButton button;
    QLabel label;
};
#endif // WIDGET_H

 在widgt.cpp文件中:

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    this->resize(240,320);
    button.setParent(this);
    button.move(40,50);
    button.setText("更换内容");
    label.setParent(this);
    label.move(40,100);
    label.setText("更换前");
    connect(&button,&QPushButton::pressed,this,&Widget::MySlot);
}
void Widget::MySlot()
{
    label.setText("更换后");
}
Widget::~Widget()
{
    delete ui;
}

在main.cpp文件中

#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

结果:

 


自定义信号和槽函数的要点

自定义槽函数要点如下。

  • 槽函数可以传入参数,但没有返回值。
  • 在 Qt5 中,任何成员函数、静态成员函数、全局函数及 Lambda 表达式都可以作为槽函数。与信号函数不同,槽函数必须自己完成实现代码。槽函数就是普通的成员函数,因此也会受到public、private 等访问控制关键字的影响。( 如果信号是私有的,这个信号就不能在类的外面连接,而类中本来就可以直接传递,因此这种限制也就没有任何意义。)

 自定义信号和槽需要注意的事项有以下几个。

  • 发送者和接收者都需要 QObject的派生类(当然,槽函数是全局函数、Lambda 表达式等无须接收者的时候除外 )。
  • 使用 signals 标记信号,信号是一个函数声明,返回 void,不需要实现函数代码。
  • 使用 emit 在恰当的位置发送信号。
  • 可以在 main.cpp 中使用QObject::connect()函数连接信号和槽函数。
  • 任何成员函数、静态成员函数、全局函数及Lambda 表达式都可以作为槽函数。

 Q_OBJECT

        在Qt中,如果一个类要使用信号和槽的功能,就必须在其中声明Q_OBJECT,类的定义的第一行就写上了 Q_OBJECT。不管是不是使用信号和槽,都应该添加 O_OBJECT宏,这个宏为类提供了信号和槽机制、国际化机制以及Qt提供的不基于 C++ RTTI的反射能力。其他很多操作都会依赖于这个宏,即使类中不需要使用信号和槽,也需要添加这个宏,否则会出现编译错误。


http://www.niftyadmin.cn/n/5473637.html

相关文章

《BERT》论文笔记

原文链接&#xff1a; [1810.04805] BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding (arxiv.org) 原文笔记&#xff1a; What&#xff1a; BETR&#xff1a;Pre-training of Deep Bidirectional Transformers for Language Understand…

SpringBoot3整合RabbitMQ之二_简单队列模型案例

SpringBoot3整合RabbitMQ之二_简单队列模型案例 文章目录 SpringBoot3整合RabbitMQ之二_简单队列模型案例1. 简单队列模型1. 消息发布者1. 创建简单队列的配置类2. 发布消费Controller 2. 消息消费者3. 输出结果 1. 简单队列模型 简单队列模型就是点对点发布消息&#xff0c;有…

ZYNQ学习Linux 基础外设的使用

基本都是摘抄正点原子的文章&#xff1a;《领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf》&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 工程的创建参考&#xff1a;《ZYNQ学习之Petalinux 设计流程实战》 一、GPIO 之 LED 的使…

计算机毕业设计选题之基于SSM的旅游管理系统【源码+PPT+文档+包运行成功+部署讲解】

&#x1f493;项目咨询获取源码联系v&#x1f493;xiaowan1860&#x1f493; &#x1f6a9;如何选题&#xff1f;&#x1f351; 对于项目设计中如何选题、让题目的难度在可控范围&#xff0c;以及如何在选题过程以及整个毕设过程中如何与老师沟通&#xff0c;有疑问不清晰的可…

01.IDEA中出现Cannot resolve symbol ‘SpringApplication异常

试了很多次&#xff0c;看了这篇文章终于发现了问题。IDEA解决springboot工程中Cannot resolve symbol SpringApplication异常-CSDN博客 我存在的问题在于Maven home path有误&#xff0c;改正之后就没有问题&#xff0c;不标红了。

使用深度学习识别英文字母和数字

在本教程中&#xff0c;我们将使用深度学习技术来识别包含英文字母和数字的图像。我们将使用Python和TensorFlow来构建和训练模型&#xff0c;并使用OpenCV来处理图像。 步骤 1: 准备数据集 首先&#xff0c;我们需要准备一个包含英文字母和数字的数据集。我们将从网上下载一个…

CTF之GET和POST

学过php都知道就一个简单传参&#xff0c;构造payload:?whatflag得到 flag{3121064b1e9e27280f9f709144222429} 下面是POST那题 使用firefox浏览器的插件Hackbar勾选POST传入whatflag flag{828a91acc006990d74b0cb0c2f62b8d8}

在macOS系统上安装CERN ROOT数据分析框架

在 macOS 上从预编译二进制文件安装 CERN ROOT CERN ROOT 是一个功能强大的框架,是一个用于处理和操作数据的 C++ 库。 对于初学者来说,库的设置和使用可能会带来困难,因为: 要设置该库,用户必须熟悉基本的命令行工具。要从多个源代码中编译一个独立的可执行文件,必须了…