Qt 6.x中的信号和槽介绍及示例

news2024/9/27 23:31:26

      信号(signals)和槽(slots)用于对象之间的通信,Qt使用信号和槽完成了事件监听操作。信号和槽机制是Qt的核心特性,可能也是与其它框架提供的特性最大的不同之处。信号和槽是通过Qt的元对象系统(Meta-Object system)实现的,Qt的元对象系统使信号和槽成为可能。其它框架或工具包可能使用回调(callback)来实现这种通信。信号和槽类似于设计模式中的观察者模式。
      在Qt中,我们有一个回调技术的替代方案:signals and slots。当特定事件发生时,发出信号(a signal is emitted).Qt的widgets(控件或部件)有许多预定义的信号,但我们总是可以subclass widgets,向它们添加我们自己的信号。槽是响应特定信号而调用的函数。Qt的widgets有许多预定义的槽,但通常的做法是subclass widgets并添加自己的槽,这样就可以处理感兴趣的信号。
      信号和槽机制(mechanism)是类型安全的信号的签名(signature)必须与接收槽的签名相匹配(事实上,一个槽的签名可能比它接收到的信号短,因为它可以忽略额外的参数)。因为签名是兼容的,所以在使用基于函数指针的语法时,编译器可以帮助我们检测类型不匹配。基于字符串的SIGNAL和SLOT语法将在运行时检测类型不匹配信号和槽是松散耦合的(loosely coupled):发出信号的类既不知道也不关心哪个槽接收信号。Qt的信号和槽机制确保如果你将一个信号连接(connect)到一个槽,此槽将在正确的时间用信号的参数被调用。信号和槽可以接受任意数量的任意类型的参数。它们是完全类型安全的。
      所有继承自QObject或它的子类(例如,QWidgets)的类都可以包含信号和槽。当对象以其他对象可能感兴趣的方式改变其状态时,就会发出信号(Signals are emitted by objects when they change their state in a way that may be interesting to other objects).这就是对象进行通信所做的全部工作。它不知道也不关心是否有任何东西在接收它发出的信号。
      槽可以用于接收信号,但它们也是普通的成员函数。就像一个对象不知道是否有任何东西接收到它的信号一样,一个槽也不知道它是否有任何信号连接到它(Just as an object does not know if anything receives its signals, a slot does not know if it has any signals connected to it)。
      你可以将任意数量的信号连接到单个槽(多个信号可以连接到一个槽),一个信号可以连接到任意数量的槽(一个信号可以和多个槽相连)。甚至可以将一个信号直接连接到另一个信号(这将在第一个信号发出(emit)时立即发出第二个信号)。如下图所示:https://doc.qt.io/qt-6/signalsandslots.html

      信号:当对象(object)的内部状态(internal state)以对象的客户端或所有者可能感兴趣的某种方式发生变化时,对象就会发出信号。信号是公共访问函数,可以从任何地方发出,但我们建议只从定义信号及其子类的类发出
      当信号发出时,连接到它的槽通常立即执行,就像普通的函数调用一样。当这种情况发生时,信号和槽机制完全独立于任何GUI事件循环。一旦所有槽都返回,emit语句后面的代码就会执行当使用队列连接(queued connections)时,情况略有不同;在这种情况下,emit关键字后面的代码将立即继续,槽将在稍后执行。
      如果几个槽连接到一个信号,那么当信号发出时,这些槽将按照它们连接的顺序(in the order they have been connected)依次执行。
      信号由moc(Meta-Object Compiler, 元对象编译器)自动生成,不能在.cpp文件中实现。它们永远不能有返回类型(使用void)如果C++文件中的类声明中包含了宏Q_OBJECT,则编译时会生成一个新的cpp文件,默认文件名为moc_项目名称.cpp。信号也是一个函数,只是我们只管写信号声明,而信号实现Qt会帮助我们自动生成槽函数不仅需要写函数声明,其实现也必须自己来实现当Qt发现signals标志后,默认为我们是在定义信号,Qt则帮助我们生产了信号的实现体。当Qt发现slots标志时,Qt元对象系统是用来解析槽函数时用的。
      关于参数的注意事项:如果信号和槽不使用特殊类型(special types),它们就更容易被重用。
      槽:当连接到槽的信号发出时,槽被调用。槽是普通的C++函数,可以正常调用;它们唯一的特点是信号可以连接到它们。
      因为槽是普通的成员函数,所以直接调用时遵循普通的C++规则。然而,作为槽,任何组件(component)都可以通过signal-slot连接调用它们,无论其访问级别如何。这意味着从任意类的实例发出的信号可能导致在不相关的类的实例中调用私有槽
      你还可以将槽定义为vritual,我们发现这在实践中非常有用。
      与回调相比,信号和槽稍微慢一些,因为它们提供了更大的灵活性,尽管对于实际应用程序来说这种差异是微不足道的。
      注意:当与基于Qt的应用程序一起编译时,其它定义名为信号或槽的变量的库可能会导致编译器警告和错误。若要解决此问题,请#undef有问题的预处理器符号。

      所有包含信号或槽的类都必须在其声明的顶部提及(mention) Q_OBJECT.它们还必须(直接或间接)从QObject派生。QObject是所有类的基类。

      槽函数:on_控件ID_控件函数(参数), 不需要通过connect函数将信号与槽关联起来
      (1).必须是on_开头;
      (2).控件ID是object name,是唯一的;
      (3).控件函数:控件自身具有的函数,如按键的clicked()

      自定义信号注意事项:
      (1).只能是类的成员函数;
      (2).返回值必须是void类型;
      (3).需要使用signals关键字进行声明;
      (4).只需要声明;
      (5).通过emit发送信号,也可以不用emit直接调用;
      (6).支持重载.

      自定义槽函数注意事项:
      (1).可以是类的成员函数、全局函数、静态函数、Lambda表达式;
      (2).返回值必须是void类型;
      (3).支持重载;
      (4).参数是用来接收信号传递的数据,信号传递的数据就是信号的参数;
      (5).使用slots关键字进行声明,也可以省略.

      通过QObject::connect函数关联信号和槽函数。connect函数是在QObject中实现的,并不局限于GUI,因此,只要继承QObject类,就可以使用信号和槽机制connect函数一般写在窗口的构造函数中,相当于在事件产生之前在Qt框架中先进行注册。
      Qt5及后,不推荐使用SIGNAL/SLOT老式用法,如:connect(btn, SIGNAL(clicked()), this, SLOT(close())); 推荐使用:connect(btn, &QPushButton::clicked, this, &MainWindow::close); 老式写法,在编译的时候即使信号或槽不存在也不会报错,但是在执行的时候无效。新方法,如果编译的时候信号或槽不存在是无法编译通过的,相当于编译时检查,不容易出错。

      注:以上内容来自于网络整理

      以下为测试代码:

      Widgets_Test.h:原名为mainwindow.h

#pragma once

#include <qstring.h>
#include <QtWidgets/QMainWindow>
#include "ui_Widgets_Test.h"

class Widgets_Test : public QMainWindow
{
    Q_OBJECT

public:
    Widgets_Test(QWidget *parent = nullptr);
    ~Widgets_Test();

signals:
    void get_address(const QString& str);

private slots:
    // 槽函数:on_<object name>_<signal name> : 自动关联,无需使用connect将信号与槽关联
    // 在Qt Creator中,打开ui,然后选中按钮,点击右键,然后选择"转到槽...",双击clicked(),会自动生成槽函数
    void on_csdn_address_clicked();
    void on_github_address_clicked();

    void set_address(const QString& str);

private:
    Ui::Widgets_TestClass ui;
};

      Widgets_Test.cpp:原名为mainwindow.cpp

#include "Widgets_Test.h"
#include <string>
#include <qdebug.h>
#include <qmessagebox.h>

Widgets_Test::Widgets_Test(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    //connect(this, SIGNAL(get_address(QString)), this, SLOT(set_address(QString))); // 不推荐使用SIGNAL, SLOT
    connect(this, &Widgets_Test::get_address, this, &Widgets_Test::set_address);
}

Widgets_Test::~Widgets_Test()
{}

void Widgets_Test::on_csdn_address_clicked()
{
    emit get_address("csdn");
    //get_address("csdn"); // 可以省略emit
}

void Widgets_Test::on_github_address_clicked()
{
    emit get_address("github");
}

void Widgets_Test::set_address(const QString& str)
{
    // 试试std::string到QString的转换
    const static std::string csdn = "https://blog.csdn.net/fengbingchun/", github = "https://github.com/fengbingchun";

    QString ret = "^_^";
    if (str == "csdn") {
        ret = QString::fromStdString(csdn);
    } else if (str == "github") {
        ret = QString::fromStdString(github);
    }

    //qDebug() << ret;
    QMessageBox::information(nullptr, "Result", ret, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
}

      main.cpp:

#include "Widgets_Test.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <qpushbutton.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widgets_Test w;

    // 信号、槽:点击Close按钮后关闭窗口
    QPushButton button("Close", &w);
    button.move(QPoint(500, 350));
    button.resize(50, 20);

    // Qt预定义的信号和槽
    QObject::connect(&button, &QPushButton::clicked, &w, &Widgets_Test::close);

    w.show();
    return a.exec();
}

      执行结果如下图所示:点击csdn address按钮,会弹出对话框,显示csdn地址;点击github address按钮,会弹出对话框,显示github地址;点击Close按钮,关闭应用程序

       GitHub:https://github.com/fengbingchun/Qt_Test

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

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

相关文章

【寒假每日一题】DAY.10 杨辉直角(等腰)三角

目录 一、杨辉直角三角 思路 按部就班 代码实现 二、杨辉等腰三角 注&#xff1a;由于VS不支持变长数组&#xff0c;这里我就用n4来写 一、题目名称 题目内容&#xff1a; 输入一个数n&#xff0c;在屏幕上打印n行n列的杨辉三角。例如&#xff1a;输入&#xff1a;4输出&am…

CSRF与XSS组合拳

目录 先介绍下这两个漏洞&#xff1a; CSRF XSS 实验&#xff1a; 环境&#xff1a; CSRF与反射型xss的第一拳 CSRF与存储型XSS的第二拳&#xff1a; 先介绍下这两个漏洞&#xff1a; CSRF CSRF是跨站请求伪造攻击&#xff0c;由客户端发起,是由于没有在关键操作执行时进…

美团滑块(1-18,js逆向)

网址&#xff1a;aHR0cHM6Ly9wYXNzcG9ydC5tZWl0dWFuLmNvbS9hY2NvdW50L3VuaXRpdmVsb2dpbg整体流程&#xff1a; 1、获取主页参数 2、逆向pwd、h5Fingerprint 3、请求page_data链接 4、逆向Authencation、behavior、token_ 5、最终请求验证一、获取主页参数 url_ "https:/…

信息论复习—信息论的基本概念

信息的概念&#xff1a;古代的信息技术&#xff1a;现代的信息技术信息与消息的关系&#xff1a;消息&#xff1a;用文字、符号、数据、语言、音符、图片、图像等能够被人们感觉器官所感知的形式&#xff0c;把客观物质运动和主观思维活动的状态表达出来就称为消息。信息&#…

Flink 实时计算DIM层实现方案

1 概述 DIM层设计要点&#xff1a; &#xff08;1&#xff09;DIM层的设计依据是维度建模理论&#xff0c;该层存储维度模型的维度表。 &#xff08;2&#xff09;DIM层的数据存储在 HBase 表中DIM 层表是用于维度关联的&#xff0c;要通过主键去获取相关维度信息&#xff0c;…

html2canvas移动端使用问题及解决

1、jsbridge重复调用问题现象&#xff1a;与移动端进行通信&#xff0c;通过<script>标签里的jsbridge.js来调用端上的接口&#xff0c;在调用接口之后&#xff0c;调用html2canvas来生成图片&#xff0c;发现刚才调用的接口又被调用了一次解决方案&#xff1a;在html2ca…

比YOLOv8还要强的YOLOv6 v3.0

论文地址&#xff1a;https://arxiv.org/pdf/2301.05586.pdf 开源地址&#xff1a;https://github.com/meituan/YOLOv6 YOLOv6 v3.0的主要贡献简述如下&#xff1a; 对检测器的Neck部件进行了翻新&#xff0c;引入BiC(Bi-directional Concatenation)提供更精确的定位信息&…

好看的vscode深色主题,搜索主题名称即可设置

1.watermelon-theme 西瓜颜色的主题&#xff0c;满满的夏天感&#xff0c;红色交替的温柔。 2.Kawaine Theme 好看的粉色系主题&#xff0c; 3. Feminine Color Theme 很适合女孩子的一个主题&#xff0c;好看如其名。 4.pinkFlower-theme 这个真的超粉&#xff0c;很好看的…

Python采集常用:谷歌浏览器驱动——Chromedriver 插件安装教程

人生苦短 &#xff0c;我用Python 趁放假&#xff0c;偷偷卷起来&#xff01;&#xff01;&#xff01; 我们经常要使用谷歌浏览器驱动&#xff0c; 今天分享下这个Chromedriver 插件的安装方法。 一、打开谷歌浏览器打开设置面板 二、查看当前谷歌浏览器版本号 三、点击插件…

计算机取证科普性基础

内容为美亚柏科公开课笔记。 1 Windows系统与取证 1.1 存储介质取证概述 专业名词 未分配空间文件残留区 物理大小逻辑大小文件大小物理大小-逻辑大小 临时文件 C:\Windows\Temp*.tmpC:\Documents and Settings\Username\Local Setting\Temporary Internet FilesC:\Documen…

接口超时分析

原文&#xff1a;接口突然超时&#xff01;&#xff01;&#xff01; 1、网络异常 1.1、网络抖动 经常上网的我们&#xff0c;肯定遇到过这样的场景&#xff1a;大多数情况下我们访问某个网站很快&#xff0c;但偶尔会出现网页一直转圈&#xff0c;加载不出来的情况。 有可…

centos7 升级 gcc 版本

查看动态库版本 strings /usr/lib64/libstdc.so.6 | grep CXXABI查找gcc生成的最新动态库 find / -name "libstdc.so*"方法一&#xff1a; 1、查看当前gcc版本 #默认4.8.5 g -v 或者 gcc --version2、下载gcc源码&#xff08;10.2.0&#xff09; wget https://f…

2022.12青少年软件编程(Python)等级考试试卷(六级)

2022.12.10青少年软件编程(Python)等级考试试卷(六级) 一、单选题(共25题,共50分) 1.数据文件“abc.txt”中包含若干个英文单词,如图所示: 读取文件“abc.txt”中数据的Python程序段如下: file = abc.txt word_b = [] for word in open(file): if w…

spring boot支持https请求(建议收藏)

文章目录前言一、借助keytools二、详细步骤三、配置spring项目支持https总结前言 博主个人社区&#xff1a;开发与算法学习社区 博主个人主页&#xff1a;Killing Vibe的博客 欢迎大家加入&#xff0c;一起交流学习~~ 众所周知&#xff0c;http是不安全的协议&#xff0c;那么要…

OC/Swift 技术 链接跳转外置(内置)Safari/加载网页(源码)

一直觉得自己写的不是技术&#xff0c;而是情怀&#xff0c;一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的&#xff0c;希望我的这条路能让你们少走弯路&#xff0c;希望我能帮你们抹去知识的蒙尘&#xff0c;希望我能帮你们理清知识的脉络&#xff0…

javascript将地址转换为经纬度_调用百度地图API_地址解析

1、注册账号和密钥申请 百度地图 选择&#xff0c;开发文档->javascriptAPI 进入后先进行账号和密钥获取&#xff0c;并且申请成为百度开发者&#xff0c;点击使用方法内的步骤即可跳转 获取服务密钥ak 应用类型选择浏览器端 白名单自己设置&#xff1a;只有白名单中的网站…

【博客595】从linux收包与发包过程看iptables链如何发挥作用

从linux收包与发包过程看iptables链如何发挥作用 1、linux收包过程&#xff08;以udp包为例&#xff09; 2、linux发包过程&#xff08;以udp包为例&#xff09; 3、收发包过程中iptables的hook如何发挥作用 主要分为三个部分&#xff1a; 接收数据的处理流程是&#xff1a;…

【Kubernetes 企业项目实战】04、基于 K8s 构建 EFK+logstash+kafka 日志平台(中)

目录 一、安装存储日志组件 Elasticsearch 1.1 创建名称空间 1.2 安装 elasticsearch 组件 1&#xff09;创建 headless service 服务 2&#xff09;通过 statefulset 创建 elasticsearch 集群 二、安装 kibana 可视化 UI 界面 一、安装存储日志组件 Elasticsearch 1.1 …

django框架全解

目录简介MVC与MTV模型MVCMTV创建项目目录生命周期静态文件配置&#xff08;无用&#xff09;启动django路由分组无名分组有名分组路由分发反向解析反向解析结合分组名称空间re_path与path自定义转换器视图HttpRequest常用方法HttpResponseJsonFBV和CBV模板&#xff08;前后端分…

SpringBoot+VUE前后端分离项目学习笔记 - 【24 服务器安装部署】

本节主要实现服务器购买以及服务部署 PS: 由于没有服务器本节仅做大致流程记录&#xff0c;无实际操作步骤 服务器配置安装 文档&#xff1a;docker安装centos、jdk、mysql、redis… 链接&#xff1a;http://note.youdao.com/noteshare?id6a01550a3acfbafc7cbbea4ae99c0e48&a…