Qt中的信号和信号槽(一)

news2024/10/7 2:31:53

目录

1. 信号和槽概述

信号和槽的关系

2. 标准信号槽使用

标准信号/槽

示例:

3. 自定义信号槽使用

自定义信号

自定义槽

示例:


1. 信号和槽概述

信号和槽是一种事件驱动的通信机制,广泛应用于Qt框架的事件处理、GUI编程、网络通信等方面。信号和槽机制实现了对象之间的通信和交互,使程序更加灵活、易于维护和扩展。

信号和槽机制的基本概念:

- 信号:是一种特殊的函数,用于在对象状态发生改变时通知其他对象。信号可以包含参数,但是它们不返回任何值。

- 槽:是一种接收信号的函数,用于响应特定事件。槽函数可以被连接到一个或多个信号,并且可以有自己的参数和返回值。

- 信号槽连接:通过connect函数将信号连接到一个或多个槽,可以实现对象之间的通信。当信号发射时,与该信号连接的槽将被调用。

在Qt框架中,信号和槽机制是基于元对象系统实现的。元对象系统是一种在运行时动态处理对象信息的机制,可以实现信号槽的自动连接和断开连接,避免了手动管理信号槽连接的繁琐过程。

信号和槽机制具有以下优点:

- 松耦合:通过信号和槽机制,对象之间的通信不需要知道彼此的具体实现,只需要知道信号和槽的接口即可实现通信,大大降低了对象之间的耦合度。

- 可扩展性:信号和槽机制支持多个槽连接同一个信号,也支持一个槽连接多个信号。这种机制使得程序的功能可以很容易地进行扩展,增加新的信号和槽即可实现对功能进行扩展。

- 线程安全:信号和槽机制基于元对象系统实现,可以很好地处理线程安全问题,支持在不同的线程中进行信号和槽的连接和调用,保证了程序的健壮性。

总的来说,信号和槽机制是Qt框架中非常重要的机制之一,它的灵活性和可扩展性在GUI编程、事件处理、网络通信等方面都得到了广泛的应用。

信号和槽的关系

信号和槽是一种连接对象之间的机制,是Qt框架中用于事件处理的重要机制。信号是一种特殊的函数,用于在对象状态发生改变时通知其他对象。槽是一种接收信号的函数,用于响应特定事件。信号和槽的关系可以概括为如下几个方面:

1. 信号和槽之间是一种一对多的关系:一个信号可以连接多个槽函数,一个槽函数也可以连接多个信号。这种关系可以实现对象之间的灵活通信。

2. 信号和槽之间通过connect函数进行连接:在需要实现信号和槽之间的连接时,可以使用Qt中提供的connect函数进行连接。该函数的参数包括信号的发射者、信号名称、槽函数的接收者和槽函数名称等信息。

3. 信号和槽之间是异步的:连接的信号和槽之间的函数调用是异步的,也就是说,当信号被发射时,与该信号连接的槽函数不会立即执行,而是等待事件循环。这种机制可以实现多线程通信。

4. 信号和槽之间是基于元对象系统的:在Qt框架中,信号和槽的实现是基于元对象系统(Meta-Object System)实现的。元对象系统是一种在运行时动态处理对象信息的机制,可以实现信号槽的自动连接和断开连接,避免了手动管理信号槽连接的繁琐过程。

总的来说,信号和槽是一种非常重要的机制,在Qt框架中广泛应用于事件处理、GUI编程、网络通信等方面。信号和槽机制可以帮助开发者实现对象之间的通信和交互,使程序更加灵活、易于维护和扩展。

连接信号和槽的connect()函数原型如下, 其中PointerToMemberFunction是一个指向函数地址的指针:

QMetaObject::Connection QObject::connect(
    	const QObject *sender, PointerToMemberFunction signal, 
        const QObject *receiver, PointerToMemberFunction method, 
		Qt::ConnectionType type = Qt::AutoConnection);
参数:
  - sender:   发出信号的对象
  - signal:   属于sender对象, 信号是一个函数, 这个参数的类型是函数
              指针, 信号函数地址
  - receiver: 信号接收者
  - method:   属于receiver对象, 当检测到sender发出了signal信号, 
              receiver对象调用method方法,信号发出之后的处理动作
 
//  参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

使用connect()进行信号槽连接的注意事项:

  • connect函数相对于做了信号处理动作的注册
  • 调用conenct函数的sender对象的信号并没有产生, 因此receiver对象的method也不会被调用
  • method槽函数本质是一个回调函数, 调用的时机是信号产生之后, 调用是Qt框架来执行的
  • connect中的sender和recever两个指针必须被实例化了, 否则conenct不会成功

2. 标准信号槽使用

标准信号/槽

        在Qt提供的很多标准类中都可以对用户触发的某些特定事件进行检测, 因此当用户做了这些操作之后, 事件被触发类的内部就会产生对应的信号, 这些信号都是Qt类内部自带的, 因此称之为标准信号。

        同样的,在Qt的很多类内部为我了提供了很多功能函数,并且这些函数也可以作为触发的信号的处理动作,有这类特性的函数在Qt中称之为标准槽函数。

示例(点击窗口关闭按钮,关闭窗口):

先在新建项目的mainwindow.ui界面中拖进Push Button按钮,并对其值进行修改为“closeBtn”

 

然后在mainwindow.cpp中编写以下代码,并运行

 

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}

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

 点击“关闭窗口”按钮,则窗口关闭

 

3. 自定义信号槽使用

        Qt框架提供的信号槽在某些特定场景下是无法满足我们的项目需求的,因此我们还设计自己需要的的信号和槽,同样还是使用connect()对自定义的信号槽进行连接。

如果想要在QT类中自定义信号槽, 需要满足一些条件, 并且有些事项也需要注意:

  • 要编写新的类并且让其继承Qt的某些标准类
  • 这个新的子类必须从QObject类或者是QObject子类进行派生
  • 在定义类的头文件中加入 Q_OBJECT 宏
// 在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
    Q_OBJECT
    ......
}

自定义信号

在Qt中信号的本质是事件, 但是在框架中也是以函数的形式存在的, 只不过信号对应的函数只有声明, 没有定义。如果Qt中的标准信号不能满足我们的需求,可以在程序中进行信号的自定义,当自定义信号对应的事件产生之后,认为的将这个信号发射出去即可(其实就是调用一下这个信号函数)。

自定义信号的要求和注意事项:

  1. 信号是类的成员函数
  2. 返回值必须是 void 类型
  3. 信号的名字可以根据实际情况进行指定
  4. 参数可以随意指定, 信号也支持重载
  5. 信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字
  6. 信号函数只需要声明, 不需要定义(没有函数体实现)
  7. 在程序中发射自定义信号: 发送信号的本质就是调用信号函数
    • 习惯性在信号函数前加关键字: emit, 但是可以省略不写
    • emit只是显示的声明一下信号要被发射了, 没有特殊含义
    • 底层 emit == #define emit
// 举例: 信号重载
// Qt中的类想要使用信号槽机制必须要从QObject类派生(直接或间接派生都可以)
class Test : public QObject
{
    Q_OBJECT
signals:
    void testsignal();
	// 参数的作用是数据传递, 谁调用信号函数谁就指定实参
	// 实参最终会被传递给槽函数
    void testsignal(int a);
};

自定义槽

        槽函数就是信号的处理动作,在Qt中槽函数可以作为普通的成员函数来使用。如果标准槽函数提供的功能满足不了需求,可以自己定义槽函数进行某些特殊功能的实现。自定义槽函数和自定义的普通函数写法是一样的。

下边给大家阐述一下, 自定义槽的要求和注意事项:

  1. 返回值必须是 void 类型

  2. 槽也是函数, 因此也支持重载

  3. 槽函数需要指定多少个参数, 需要看连接的信号的参数个数

  4. 槽函数的参数是用来接收信号传递的数据的, 信号传递的数据就是信号的参数

    • 举例:
      • 信号函数: void testsig(int a, double b);
      • 槽函数: void testslot(int a, double b);
    • 总结:
      • 槽函数的参数应该和对应的信号的参数个数, 从左到右类型依次对应
      • 信号的参数可以大于等于槽函数的参数个数 == 信号传递的数据被忽略了
        • 信号函数: void testsig(int a, double b);
        • 槽函数: void testslot(int a);
  5. Qt中槽函数的类型是多样的

    Qt中的槽函数可以是类的成员函数全局函数静态函数Lambda表达式(匿名函数)

  6. 槽函数可以使用关键字进行声明: slots (Qt5中slots可以省略不写)

    • public slots:
    • private slots: –> 这样的槽函数不能在类外部被调用
    • protected slots: –> 这样的槽函数不能在类外部被调用
// 槽函数书写格式举例
// 类中的这三个函数都可以作为槽函数来使用
class Test : public QObject
{
    public:
    void testSlot();
    static void testFunc();

    public slots:
    void testSlot(int id);
};

示例:

先添加一个新文件

 

 Base class选择QObject,点击下一步,完成

 再按上述方法添加一个新文件

 在ui界面中添加一个PushButton按钮,命名为need

 在test.h文件中signals一个need函数:

 

#ifndef TEST_H
#define TEST_H

#include <QObject>

class Test : public QObject
{
    Q_OBJECT
public:
    explicit Test(QObject *parent = nullptr);

signals:
    void need();

};

#endif // TEST_H

在test01.h文件中声明一个what_need函数:

 

#ifndef TEST01_H
#define TEST01_H

#include <QObject>

class Test01 : public QObject
{
    Q_OBJECT
public:
    explicit Test01(QObject *parent = nullptr);
    //槽函数
public slots:
    //槽函数
    void what_need();

};

#endif // TEST01_H

在test01.cpp中添加定义

 

#include "test01.h"
#include <QDebug>
Test01::Test01(QObject *parent)
    : QObject{parent}
{

}

void Test01::what_need()
{
    qDebug()<<"你需要什么";
}

在mainwindow.h中#include test和test01两个头文件,并且添加need按钮的槽函数,定义两个私有变量m_whatnd和m_need

 

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "test.h"
#include "test01.h"
#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    //添加need按钮的槽函数
    void needSlot();

private:
    Ui::MainWindow *ui;

    Test01* m_whatnd;
    Test* m_need;
};
#endif // MAINWINDOW_HS

在mainwindow.cpp中用connect函数连接信号和信号槽

 

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    m_whatnd = new Test01;
    m_need = new Test;
    connect(m_need,&Test::need,m_whatnd,&Test01::what_need);
    connect(ui->need,&QPushButton::clicked,this,&MainWindow::needSlot);

}

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

void MainWindow::needSlot()
{
    //发射自定义信号
    emit m_need->need();

}

运行结果(每次点击need按钮时,应用程序输出“你需要什么”):

 总结:本文讲述了Qt中的信号和信号槽的使用和相关函数,演示了标准信号槽和自定义信号槽该如何使用

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

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

相关文章

如何在教育与科研领域使用ChatGPT

ChatGPT提示是您给予ChatGPT的一系列指示&#xff0c;以便它能够按需生成结果。由于ChatGPT是一种会话型人工智能&#xff0c;因此它需要明确的指示才能生成准确的结果。 ChatGPT提示的结构通常是以指令格式呈现的。它看起来像是您在与AI交流&#xff0c;给予它执行特定任务的…

基于树莓派4B的OpenCV安装与简单应用(真速通版)

前言&#xff1a;本文为手把手教学树莓派4B的OpenCV安装与简单应用&#xff08;真速通版本&#xff09;&#xff0c;树莓派4B最为目前最新款的树莓派家族一员深受创客和开发者喜爱。树莓派4B作为一款搭载 Cortex-A72 系列芯片的板载电脑&#xff0c;其不仅可以作为简单的 MCU 进…

第三方库介绍——Protobuf库(更高效的协议)

文章目录 protobuf综述传输协议与指令创建协议编译协议介绍addressbook.pb.h文件序列化与反序列化的接口 利用soctet实现客户端与服务端传输协议Linux&#xff08;Ubuntu&#xff09;安装protoc步骤编写案例代码Cartoon.prototcpsocket.hMyTcpsocket.hclient.cppserver.cppCMak…

01.4进程原理和系统调用--->经典的CFS调度器

进程的一些正常状态 什么是进程 操作系统作为硬件的使用层&#xff0c;提供使用硬件资源的能力&#xff0c;进程作为操作系统使用层&#xff0c; 提供使用操作系统抽象出的资源层的能力。 进程&#xff1a;是指计算机中已运行的程序。进程本身不是基本的运行单位&#xff0c;…

【微服务】springboot 通用限流方案设计与实现

目录 一、背景 二、限流概述 2.1 dubbo 服务治理模式 2.1.1 dubbo框架级限流 2.1.2 线程池设置 2.1.3 集成第三方组件 2.2 springcloud 服务治理模式 2.2.1 hystrix 2.2.2 sentinel 2.3 网关层限流 三、常用限流策略 3.1 限流常用的算法 3.1.1 令牌桶算法 3.1.2 …

2023最新Java面试八股文汇总(五十万字总结版)

写在前面 今年的疫情&#xff0c;让招聘面试变得雪上加霜。已经有不少大厂&#xff0c;如腾讯、字节跳动的招聘名额明显减少&#xff0c;面试门槛却一再拔高&#xff0c;如果不用心准备&#xff0c;很可能就被面试官怼得哑口无言&#xff0c;甚至失去了难得的机会。 现如今&a…

<Linux开发>驱动开发 -之- Linux RTC 驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -之- Linux RTC 驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细…

Dubbo【 Dubbo概念(什么是分布式系统、什么是RPC、核心组件、Zookeeper注册中心 )】(一)-全面详解(学习总结---从入门到深化)

目录 Dubbo概念_什么是分布式系统 什么是分布式 Dubbo概念_什么是RPC Dubbo概念_简介 Dubbo概念_核心组件 Dubbo配置开发环境_Zookeeper注册中心 Dubbo配置开发环境_管理控制台 Dubbo入门案例_需求介绍 Dubbo入门案例_配置开发环境 Dubbo入门案例_服务生产者配置…

VLC-QT源码编译(Windows10+VS2020+MSVC20019+QT5.15)

参考VLC-Qt的编译与使用 windows10VS2019qt5.15 下载源码 VLC-QT https://github.com/vlc-qt/vlc-qt可以通过git或者直接下载ZIP文件&#xff0c;但是里面的libvlc-header和packaging没有下载下来&#xff0c;需要再自行下载。 VLC https://download.videolan.org/vlc/las…

行为型模式--备忘录模式

目录 概述 结构 案例实现 “白箱”备忘录模式 总结&#xff1a; “黑箱”备忘录模式 优缺点 优点&#xff1a; 缺点&#xff1a; 使用场景 概述 又叫快照模式&#xff0c;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这…

zeromq的学习笔记

ctx_t 在创建ctx_t时&#xff0c;会设置以下参数 _io_thread_count io线程数默认是1 _max_sockets最大socket数是1023 _starting标识设置为true,此时socket还没有创建 _terminating设置为false,在调用zmq_ctx_term时该标识会设置为true _tag设置为ZMQ_CTX_TAG_VALUE_GOOD&…

mySql和VSC++

确认主机服务里的mysql服务已打开 使用组合键“winR”运行“services.msc”&#xff0c;进入本地服务窗口&#xff1b; 2.进入本地服务窗口后&#xff0c;在右侧服务列表中&#xff0c;查找到“ mysql ”服务选项&#xff1b; 3.查找到mysql服务选项后&#xff0c;双击打开mysq…

C++ 面向对象(3)——重载运算符和重载函数

C 允许在同一作用域中的某个函数和运算符指定多个定义&#xff0c;分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明&#xff0c;但是它们的参数列表和定义&#xff08;实现&#xff09;不相同。 当您调用一个重…

FDM3D打印系列——3、常用打印材料介绍

大家好&#xff0c;我是阿赵。 FDM3D打印机一般都可以支持多种打印材料的&#xff0c;下面来介绍一下几种常用的打印材料 一、PLA 使用FDM打印&#xff0c;最常见的材料就是PLA了 PLA&#xff08;Polylactic acid&#xff09;&#xff0c;中文名为生物降解塑料聚乳酸&#…

网络安全面试题,渗透测试面试总结

1.什么是WebShell? WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的─种命令执行环境&#xff0c;也可以将其称做为─种网页后门。黑客在入侵了─个网站后&#xff0c;通常会将这些asp或php后门文件与网站服务器WEB目录下正常的网页文件混在─起&#xff0c;然后就可…

【Vue3】生命周期(钩子)函数

在 Vue 3 中&#xff0c;生命周期函数已经被重新设计为钩子函数&#xff0c;并且与 Vue 2 中的生命周期函数有所不同&#xff0c;可以在 setup 函数中使用 onXXX 形式的钩子函数来执行对应的操作。以下是选项式 API 和组合式 API 中常用的几个钩子函数对比&#xff1a; beforeC…

【Java】PriorityQueue--优先级队列

目录 一、优先级队列 &#xff08;1&#xff09;概念 二、优先级队列的模拟实现 &#xff08;1&#xff09;堆的概念 &#xff08;2&#xff09;堆的存储方式 &#xff08;3&#xff09;堆的创建 堆向下调整 &#xff08;4&#xff09;堆的插入与删除 堆的插入 堆的…

Kubernetes(k8s)容器编排组件介绍

目录 1 整体架构1.1 Master 架构1.2 Node 架构 2 k8s部署组件介绍2.1 K8s 集群架构图2.2 k8s控制组件2.2.1 控制平面2.2.2 kube-apiserver2.2.3 kube-scheduler2.2.4 kube-controller-manager2.2.5 etcd 2.3 k8s运行组件2.3.1 k8s节点2.3.2 容器集2.3.3 容器运行时引擎2.3.4 ku…

机试复试准备中--梦校真题

一、矩阵转置二、统计单词写法一&#xff1a;读取一整行写法二&#xff1a;依次读入每一个单词 三、二叉排序树&#xff08;DFS&#xff09;四、IP地址五、特殊排序六、ab&#xff08;高精度加法&#xff09;七、奇偶校验八、最大的两个数九、二叉树遍历(DFS)十、成绩排序十一、…

【C++学习】C++入门 | 引用 | 引用的底层原理 | auto关键字 | 范围for(语法糖)

写在前面&#xff1a; 上一篇文章我介绍了缺省参数和函数重载&#xff0c; 探究了C为什么能够支持函数重载而C语言不能&#xff0c; 这里是传送门&#xff0c;有兴趣可以去看看&#xff1a;http://t.csdn.cn/29ycJ 这篇我们继续来学习C的基础知识。 目录 写在前面&#x…