QT 信号(Signal)与槽(Slot)机制

一、信号(signal)与槽(slot)

在QT中,信号(signal)与槽(slot)机制是一种用于对象间通信的重要机制。它允许一个对象发出信号,而其他对象可以通过连接到该信号的槽来接收并处理这个信号。

信号是由QObject派生类中声明的特殊函数,用于表示某个事件的发生。例如,当按钮被点击时,QPushButton类会发出一个clicked()信号。每个信号都有一个唯一的名称,并且可以带有参数。

是普通的成员函数,用于接收和处理信号。槽函数可以在任何QObject派生类中定义,但必须使用特殊的宏进行声明。槽函数可以执行任意操作,包括修改对象的状态、调用其他函数等。

连接(connection)是将信号与槽关联起来的过程。通过连接,当信号发出时,与之连接的槽函数将被自动调用。连接可以在代码中手动创建,也可以使用Qt提供的可视化工具进行创建。

信号与槽机制的优势在于它们实现了松耦合的对象间通信。通过信号与槽,不同对象之间可以进行灵活的交互,而无需显式地引用彼此。这种机制使得代码更加模块化、可维护性更高,并且能够方便地实现事件驱动的程序设计。

二、元对象系统

在Qt中,元对象(Meta Object)是一种特殊的对象,用于存储类的元信息,包括类名、父类名、信号和槽等。每个继承自QObject的类都有一个对应的元对象。

元对象系统允许Qt实现一些高级功能,比如信号与槽机制、属性系统、动态属性以及对象反射等。通过元对象系统,Qt可以在运行时获取类的元信息,并且能够动态地操作这些信息。

元对象系统的核心是使用元对象宏(Q_OBJECT)来声明一个类为元对象类。当一个类被声明为元对象类时,Qt的元对象编译器(MOC)会生成额外的代码,用于处理信号与槽、属性等元信息。

通过元对象系统,Qt可以实现诸如信号与槽的自动连接、动态属性的添加与修改、对象类型的判断等功能。这使得Qt具有很强的灵活性和可扩展性,能够支持更加动态和智能的编程模式。

三、实现原理

在Qt中,信号(signal)与槽(slot)机制是元对象系统的核心组成部分。

首先,元对象系统通过使用元对象宏(Q_OBJECT)来声明一个类为元对象类。当一个类被声明为元对象类时,Qt的元对象编译器(MOC)会生成额外的代码,用于处理信号与槽、属性等元信息。

然后,信号与槽机制是元对象系统的一种实现方式。通过元对象系统,Qt可以在运行时获取类的元信息,并且能够动态地操作这些信息。而信号与槽机制则是利用了元对象系统的特性,实现了对象间的松耦合通信。

具体来说,当一个类声明了信号时,MOC会将信号的相关信息添加到该类的元对象中。而当一个类声明了槽时,MOC会将槽的相关信息添加到该类的元对象中。通过连接信号与槽,可以在运行时实现信号的发出和槽的自动调用。

因此,信号与槽机制依赖于元对象系统,通过元对象系统提供的元信息,实现了对象间的动态通信。元对象系统为信号与槽机制提供了基础,使得信号与槽能够在运行时进行连接和调用。

四、设计模式

在Qt中,信号与槽机制的底层实现使用了观察者模式(Observer Pattern)和命令模式(Command Pattern)。

观察者模式用于实现信号与槽之间的连接和通信。在观察者模式中,信号充当了被观察者(Subject),而槽函数充当了观察者(Observer)。当信号发出时,所有连接到该信号的槽函数都会被调用,实现了对象间的松耦合通信。

命令模式用于将信号与槽的调用进行封装。在命令模式中,信号的发出相当于命令的发出,而槽函数相当于命令的接收者。通过将信号与槽的调用封装成命令对象,可以实现对调用的延迟、撤销等操作。

除了观察者模式和命令模式,Qt中还使用了其他设计模式来支持信号与槽机制的实现。例如,Qt中的元对象系统使用了元数据模式(Metadata Pattern)来存储和处理类的元信息。此外,Qt还使用了工厂模式(Factory Pattern)来创建信号与槽的连接。

五、使用示例

1、使用可视化工具连接

在 UI 界面中右键按钮控件,选择【Go to slot】,可以看到该按钮控件下的信号,我们选择单击信号【clicked】,编辑器会帮我们自动在头文件、源文件添加对应的槽函数,我们只需要实现处理逻辑,

private slots:
    void on_pushButton_clicked();

2、使用 connect 函数

使用 connect 函数,将按钮 pushButton_2 的单击信号 clicked 连接到本窗口 this 的槽函数 on_pushButton_clicked,因此点击按钮2的效果等同于按钮1。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 谁发出信号,发出什么信号,谁接收信号,谁处理信号?
    
    // 使用 connection 与宏
    // connect(ui->pushButton_2,SIGNAL(clicked(bool)),this,SLOT(on_pushButton_clicked()));
    
    // 使用 connection 与指针
    // connect(ui->pushButton_2,&QPushButton::clicked,this,&MainWindow::on_pushButton_clicked);
    
    // 使用 connection 与匿名函数(当信号的处理逻辑非常简单时,使用匿名函数为佳)
    connect(ui->pushButton_2,&QPushButton,[this](){
        qDebug() << "click";
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    qDebug() << "click";
}

3、自定义信号与槽

我们自定义一个遥控器类RemoteControl与空调类AirConditioner,遥控器发出信号,空调根据指令运行,

注意创建类时勾选 Q_OBJECT 宏,接下来添加遥控器的信号,

#ifndef REMOTECONTROL_H
#define REMOTECONTROL_H

#include <QObject>

class RemoteControl : public QObject
{
    Q_OBJECT
signals:
    // 默认制冷
    void run();
    // 制热/抽湿...
    void run(QString mode);
public:
    RemoteControl();
};

#endif // REMOTECONTROL_H

可以看到我们重载了信号 run,默认情况下 run 没有参数,属于制冷模式,其他情况 run 根据参数 mode 运行不同的模式。

然后我们为空调添加槽函数,同样重载了槽函数 exec 实现运行不同模式,注意这里的重载参数必须与信号保持一致,

#ifndef AIRCONDITIONER_H
#define AIRCONDITIONER_H

#include <QObject>

class AirConditioner : public QObject
{
    Q_OBJECT
public:
    AirConditioner();
public slots:
    void exec();
    void exec(QString mode);
};

#endif // AIRCONDITIONER_H
#include "airconditioner.h"
#include <QDebug>

AirConditioner::AirConditioner() {}

void AirConditioner::exec()
{
    qDebug()<<"cold";
}

void AirConditioner::exec(QString mode)
{
    qDebug()<< mode;
}

最后我们在 mainwindow 实例化一个遥控器跟空调对象,将信号与槽函数连接起来,

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include "airconditioner.h"
#include "remotecontrol.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    AirConditioner airConditioner;
    RemoteControl remoteControl;
    connect(&remoteControl,SIGNAL(run()),&airConditioner,SLOT(exec()));
    connect(&remoteControl,SIGNAL(run(QString)),&airConditioner,SLOT(exec(QString)));
    // emit 可省略
    emit remoteControl.run();
    remoteControl.run("hot");

}

MainWindow::~MainWindow()
{
    delete ui;
}

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

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

相关文章

电容笔品牌排行榜:2024五款便宜好用的电容笔极力推荐!

iPad作为我们最常使用的平板&#xff0c;我们想体验iPad的高效使用&#xff0c;丝滑体验&#xff0c;电容笔已经成为许多人的必备工具之一。Apple Pencil适用于专业绘图&#xff0c;一千的售价着实太高&#xff0c;如果普通学生党&#xff0c;用户使用选一款好的电容笔平替&…

多进程编程及相关函数

文章目录 查看系统中的进程进程标识进程创建进程终止僵尸进程守护进程和孤儿进程wait函数exec函数system函数 程序是存放在磁盘文件中的可执行文件。程序的执行实例被称为进程&#xff0c;进程具有独立的权限与职责。 每个进程运行在其各自的虚拟地址空间中&#xff0c;进程之间…

数智赋能|智慧变电站数字孪生解决方案

当今世界&#xff0c;绿色发展已经成为一个重要趋势&#xff0c;中国、欧盟、北美纷纷发布了通过低碳化、电气化、网络化、智能化全面进行能源结构变革&#xff0c;推进碳达峰、碳中和进程的战略举措。落实绿色发展目标&#xff0c;能源是主战场&#xff0c;电力是主力军&#…

用DataGrip连接hive时报错:User: root is not allowed to impersonate plck5,解决方法

你可以尝试关闭主机校验 修改hive安装目录下conf/hive-site.xml,将hive.server2.enable.doAs设置成false <property><name>hive.server2.enable.doAs</name><value>false</value><description>Setting this property to true will have H…

python 处理png图片无损压缩

代码利用了Pillow库来处理图片的压缩&#xff0c;并使用了 glob 模块来搜索所有的 .png 文件。这个脚本应该能够按照当前的编写来完成预期的工作。 请注意&#xff0c;compress_level9 指定了Pillow保存PNG图片时采用的最大压缩等级。这确保了每张图片都被以可能的最小文件大小…

二叉搜索树(二叉排序树,二叉查找树)(附图详解+代码实现+应用分析)

最近学习了有关搜索二叉树的相关知识&#xff0c;在此特意将该知识进行总结分享&#xff0c;希望对大家有所帮助。 文章目录 一.二叉搜索树1.1二叉搜索树的概念1.2二叉搜索树的操作&#xff08;含思路分析代码实现&#xff09;1.2.1二叉搜索树的查找&#xff08;递归实现看最后…

如何在Ubuntu系统使用Docker搭建MongoDB结合内网穿透实现公网连接

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

城市排涝与海绵城市规划设计中的水文水动力模拟技术应用

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本次培训将聚焦于综合利用GIS及CAD等工具高效地进行大规模城市排水系统水力模型的建立&#xff0c;利用SWMM实现排水系统水力模拟。讲解…

如何本地部署Imagewheel并实现无公网IP远程连接打造个人云图床

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

Linux文件系列:磁盘,文件系统,软硬链接

Linux文件系列:磁盘,文件系统,软硬链接 一.磁盘相关知识1.磁盘机械构成2.磁盘物理存储3.磁盘逻辑存储1.LBA地址2.磁盘的分区和分组 二.文件系统和inode1.inode结构体2.文件系统1.Super Block(超级块)2.Group Descriptor Table(块组描述表GDT)3.inode Table4.Data Blocks5.Block…

vue3+threejs新手从零开发卡牌游戏(八):关联卡组和手牌区、添加初始化卡组和初始化手牌逻辑

首先我们优化下之前的代码&#xff0c;先加载游戏资源&#xff0c;然后再初始化场景&#xff0c;由于目前只有一个font字体需要加载&#xff0c;所以我们将之前game/deck/p1.vue中的font相关代码迁移到game/index.vue下&#xff0c;同时使用async和await处理异步加载&#xff0…

基于Scapy国内城市空气质量数据采集系统设计与实现

代码和完整的报告在文章最后 城市空气质量数据采集系统设计与实现 &#x1f3d9;️ 研究背景 &#x1f32c;️ 城市化与环境挑战&#xff1a;随着城市化进程的加快&#xff0c;环境污染问题&#xff0c;尤其是空气质量问题&#xff0c;已成为公众关注的焦点。数据监测的重要性…

Windows安装配置国产达梦数据库、配置Python接口

文章目录 前言1.下载安装达梦数据库2.配置达梦环境变量3.安装Microsoft Visual C 14.04.安装达梦Python接口dmpython5.测试验证 总结 前言 达梦数据库&#xff08;Dameng Database&#xff09;是由武汉达梦数据库股份有限公司开发的一款高性能的关系型数据库管理系统。该数据库…

关于短群签名论文阅读

参考文献为2004年发表的Short Group Signatures 什么群签名&#xff1f; 群签名大致就是由一组用户组成一个群&#xff0c;其中用户对某条消息的签名&#xff0c;改签名不会揭示是哪一个用户签署的&#xff0c;签名只能表明该消息确实是来自该群的签名。对于群还有一个群管理者…

蓝桥杯算法 - DP

上一篇&#xff1a;[[蓝桥杯算法-排序、递归、全排列]] 动态规划&#xff08;dp&#xff09; dp即动态规划&#xff0c;常用于&#xff1a;数学&#xff0c;计算机科学&#xff0c;管理学&#xff0c;经济和生物信息学。 dp在生活中也很常见&#xff0c;如&#xff1a;你今天…

【随笔】oh-my-posh(Windows power shell为例)

Oh My Posh 是一个适用于任何 shell 的自定义提示引擎&#xff0c;能够使用函数或变量调整提示字符串。 文章目录 一、安装oh-my-posh二、安装Nerd 字体三、oh-my-posh 初始化四、更换主题 一、安装oh-my-posh GitHub repo&#xff1a;https://github.com/JanDeDobbeleer/oh-m…

情感视频素材怎么来的?(情感语录的视频素材在哪里找)

很多小伙伴觉得情感类型的短视频账号用户多&#xff0c;都想要进入分一杯羹&#xff0c;那么这些创作素材去哪里找呢&#xff0c;下面分享几个非常使用的找情感短视频素材的办法。 1&#xff0c;蛙学网 说到情感视频素材的短视频&#xff0c;作为一个专业的短视频素材网站&am…

2024年云服务器ECS价格表出炉——腾讯云

腾讯云服务器多少钱一年&#xff1f;61元一年起。2024年最新腾讯云服务器优惠价格表&#xff0c;腾讯云轻量2核2G3M服务器61元一年、2核2G4M服务器99元一年可买三年、2核4G5M服务器165元一年、3年756元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、312元一年、8核…

nodeJs中实现连表查询

nodeJs中实现连表查询 router.post(/getOrder, async function(req, res, next) {let userId req.body.phone;let sql select * from orders where userId?;let orders await new Promise((resolve, reject) > {connection.query(sql, [userId], function(error, resul…

一分钟在Solana链创建代币教程

只需要 1 分钟就可以创建自己的SOLANA代币 1、连接Solana钱包2、填写代币信息创建3、创建成功 Solana 是一个基于区块链技术的高性能、去中心化的智能合约平台&#xff0c;旨在为开发者提供高度可扩展和低成本的区块链基础设施。通过其创新的共识机制和高吞吐量的网络架构&…