Qt应用开发(基础篇)——信号槽 Signals and Slots

news2024/11/25 6:33:30

一、前言

        Qt成为我们今天拥有的灵活而舒适的工具,除了友好和能够快速开发设计师界面,信号槽机制是最大的核心特征,也是区别于其他开发框架最大的优势。

        Qt的信号槽作用于两个对象之间的通信。当一个对象发生了改变,它希望其他关心它的对象能够了解到这些变化。比如一个编辑框A的数据发生了改变,而编辑框B的需要根据A的值发生数据变化,这时候我们使用信号槽机制,A产生数据变化信号,B响应信号做自身数据做改变。

        我们用来表达算法的语法会显著影响代码的可读性和可维护性。Qt的信号和槽的语法在实践中被证明是非常成功的。语法直观使用简单易于阅读这可以帮助程序员从一开始就正确地进行设计,甚至不必考虑设计模式。这满足安全和高效的图形用户界面编程,Qt希望我们构建更干净、更安全、更符合UNIX精神的系统。

二、Signals and Slots

        要实现对象之间的通讯方法有很多。

        1)初学者可能会通过定时器检测目标对象的属性变化而动作,这类方法缺点很明显,代码乱、耗资源、效率低、无法直接传递多个参数等等。

        2)资深的程序员会使用回调callback机制,这是一种函数指针的用法,想让别人的代码执行自己的代码。把自身需要执行的代码写在一个函数里面,让目标对象去调用此函数,实现对象间的通讯。但是如果多对象类都想要关心目标对象的状态变化,此时需要维护一个列表,以存放多个回调函数的地址(函数指针),对于每一个被关注的对象,都需要做类似的工作,并且对象需要动态销毁的时候,还需要关注这些函数指针的回收,这样的设计效率低且不灵活。

        3)信号槽机制类似于设计模式中的观察者模式(当一个对象状态发生改变的时候,所有依赖于它的对象都得到通知并被自动更新)。被观察者发出信号Signals,观察者监听信号,设计槽函数Slots关联信号实现动作。

值得一提的是,信号槽与回调函数的区别,是面试中经常出现的问题。

信号槽优点

        1)松耦合性

        目标对象不需要知道哪个对象关心自己,发出的信号类似于广播,如果有人对信号感兴趣,使用connect连接信号与自身的处理槽函数即可。而回调函数需要目标对象去处理对自己感兴趣的全部对象的函数指针。耦合性明显Qt信号槽机制更优。

        2)类型安全

        需要关联的信号槽的签名需要是相同的,即参数型号、参数个数必须一致。如果不一致的话编译器会报错。

        3)灵活性

        信号槽机制支持一个信号多个槽响应,也可以一个槽响应多个信号,还可以直接信号触发信号(适用于逻辑层信号夹带数据不需要处理直接转发)。

        4)内存安全

        信号槽机制在UI编程上具备优势,能够帮助程序员环节内存泄漏问题,当应用程序创建了一个具有父窗口部件的对象时,该对象被加入父窗口的child列表,当父窗口被销毁时,child列表中的对象被一一删除,子类释放的顺序与构造顺序相反。

信号槽缺点

        1)速度较慢。

        与回调函数相比,信号和槽机制运行速度比直接调用非虚函数慢10倍。照官方说法是需要定位接收信号的对象需要遍历全部关联槽需要编组和接祖传递参数。但依旧能够满足大多数应用的需求,因为1秒钟可以出发200万次这样的信号(i586-500机器,1个信号绑定一个槽函数,绑定两个1秒可以触发120万次)。

信号槽连接类型

        connect连接信号槽第五个参数为连接类型,通常情况下默认为Qt::AutoConnection,自动设置。

类型描述
Qt::AutoConnection如果信号与槽在同一个线程中则为Qt::DirectConnection直连、否则为Qt::QueuedConnection队列。
Qt::DirectConnection直连,发出信号的时候立刻调用槽函数
Qt::QueuedConnection队列,信号与槽不同线程时,使用此类型
Qt::BlockingQueuedConnection阻塞队列,等待槽函数返回,信号和槽不可在同一个线程,否则死锁
Qt::UniqueConnection一个标识,与上述几种组合使用,避免相同信号槽多次连接

信号槽使用注意事项

        1)默认情况下信号槽被多次连接,导致触发信号的时候槽函数就会被多次调用。可以使用Qt::UniqueConnection解决此问题。       

        2)Qt::BlockingQueuedConnection等于一个阻塞的机制,子线程执行信号必须等待主线程返回才会继续往下走,默认不阻塞

        3)多线程中,信号槽连接类型为Qt::QueuedConnection,所以信号触发的时候不会马上执行槽函数,存在实时性的风险

        4)信号触发的速度过快,而槽函数响应不过来。比如当你做一个视频播放器,摄像头的数据一直在刷新,但是界面上刷新不过来,槽函数处理的速度比不上信号触发的速度,如果这时候使用的是Qt::DirectConnection,导致程序可能异常。

        5) 信号槽传递的参数必须是Qt的元对象系统所知道的类型,因为Qt需要复制参数以将它们存储在后台的事件中,否则编译会报错如果需要使用自定义类型作为参数传递,使用Q_DECLARE_METATYPE()注册它。

        6)所有信号的声明都是公有的,所以不能在signals前面加public,private,proteed

        7)信号没有返回值,只需要声明不需要定义。

        7)自定义类必须直接或间接继承自QObject类,并且开头私有声明包含Q_OBJECT,才能使用信号槽机制。

信号槽连接

1)传统写法-暴露参数

QLabel *label = new QLabel;
QScrollBar *scrollBar = new QScrollBar;
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
                  label,  SLOT(setNum(int)));
//带连接类型
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
                  label,  SLOT(setNum(int)),Qt::AutoConnection);

2)进阶写法-隐藏参数

QLabel *label = new QLabel;
QLineEdit *lineEdit = new QLineEdit;
QObject::connect(lineEdit, &QLineEdit::textChanged,
                  label,  &QLabel::setText);

//带连接类型
QObject::connect(lineEdit, &QLineEdit::textChanged,
                  label,  &QLabel::setText,Qt::AutoConnection);

3)直接触发当前函数

void someFunction();
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::clicked, someFunction);
//带连接类型
QObject::connect(button, &QPushButton::clicked, someFunction,
Qt::AutoConnection);

4)Lambda表达式

 QByteArray page = ...;
 QTcpSocket *socket = new QTcpSocket;
 socket->connectToHost("qt-project.org", 80);
 QObject::connect(socket, &QTcpSocket::connected, [=] () {
         socket->write("GET " + page + "\r\n");
     });

//带连接类型
 QObject::connect(socket, &QTcpSocket::connected, [=] () {
         socket->write("GET " + page + "\r\n");
     },Qt::AutoConnection);

识别信号来源

       当有多个对象发送信号都通过一个槽来处理的时候,我们就需要在槽中识别出这些信号然后做相应的处理。

        多个lineEdit编辑框当内容发送变化的时候,我们统一设计一个槽函数来做处理,使用sender()返回发送信号的指针。

void QMainWindows::textChaned(QString str)
{
    QLineEdit* edit = dynamic_cast<QLineEdit*>(sender())
    if (edit == ui->Edit_name){
         //do something   
    }
    else if (edit == ui->Edit_number){
        //do something   
    }
}

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

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

相关文章

Windows下安装 Redis

目录 1.下载 1.1.Redis官网 1.2.github下载地址 2.安装步骤 2.1.解压Redis压缩包 2.2.创建临时服务 2.3.启动客户端 2.4.注册Redis服务 3.总结 4.致谢 1.下载 1.1.Redis官网 Download | Redis Redis 官方网站没有提供 Windows 版的安装包&#xff0c;但可以通过…

Django实现音乐网站 ⑻

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对单曲原有功能的基础上进行部分功能实现和显示优化。 目录 新增编辑 歌手下拉显示修改 设置歌曲时长 安装eyed3库 获取mp3时长 歌曲时长字段修改 重写save方法 增加歌手单曲数量 查询歌手单曲数量 …

算法通关村——二分查找在拓展中的应用

1. 山脉数组的峰顶索引 山脉数组的峰顶索引 符合下列属性的数组 arr 称为 山脉数组 &#xff1a; arr.length > 3 存在 i&#xff08;0 < i < arr.length - 1&#xff09;使得&#xff1a; arr[0] < arr[1] < … arr[i-1] < arr[i] arr[i] > arr[i1] >…

企业计算机被_locked勒索病毒攻击如何处理及后期如何做好预防工作

随着信息技术的普及和不断发展&#xff0c;勒索病毒攻击已成为企业面临的一项严峻挑战。近期&#xff0c;山西某医药公司的计算机服务器被_locked勒索病毒攻击&#xff0c;导致企业的许多重要数据被加密&#xff0c;当发现企业的服务器被该勒索病毒攻击时&#xff0c;该企业的做…

初识mysql数据库之引入mysql客户端库

目录 一、下载第三方库 1. 准备工作 1. 使用mysql官网提供的库 2. yum源安装 二、测试第三方库是否可用 三、mysql常用接口介绍 1. 查看官方文档 2. 初始化 3. 关闭mysql 4. 连接mysql 5. 下达sql指令 四、一个简单的C客户端库连接mysql程序 1. 头文件 2. 初始化…

maven 删除下载失败的包

本文介绍了当Maven包报红时&#xff0c;使用删除相关文件的方法来解决该问题。文章详细说明了_remote.repositories、.lastUpdated和_maven.repositories文件的作用&#xff0c;以及如何使用命令行删除这些文件。这些方法可以帮助开发者解决Maven包报红的问题&#xff0c;确保项…

赛码网-圈地运动 100%AC代码(C)

———————————————————————————————————— ⏩ 大家好哇&#xff01;我是小光&#xff0c;嵌入式爱好者&#xff0c;一个想要成为系统架构师的大三学生。 ⏩最近在准备秋招&#xff0c;一直在练习编程。 ⏩本篇文章对赛码网的圈地运动 题目做一…

LeetCode 热题 100 JavaScript -- 74. 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非递减顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 …

迁移协调器:方法和模式

Migration Coordinator &#xff08;迁移协调器&#xff09;是一款完全免费的工具&#xff0c;内置于 NSX Data Center 中&#xff0c;可帮助将NSX for vSphere迁移到 NSX&#xff08;又名 NSX-T&#xff09;。Migration Coordinator最初是在 NSX-T 2.4 中引入的&#xff0c;有…

在外SSH远程连接Ubuntu系统

在外SSH远程连接Ubuntu系统【无公网IP】 文章目录 在外SSH远程连接Ubuntu系统【无公网IP】前言1. 在Ubuntu系统下安装cpolar软件2. 完成安装后打开cpolar客户端web—UI界面3. 创建隧道取得连接Ubuntu系统公网地址4. 打开Windows的命令界面并输入命令 前言 随着科技和经济的发展…

RK3568 lunch新增设备

rk3568 android9.0 &#xff0c;32位平台 1.进入devices/rockchip/rk356x/ 将rk3568_box_32 拷贝一份&#xff0c;命名为hdx6 2.打开vendorsetup.sh,添加lunch选项 add_lunch_combo hdx6-user add_lunch_combo hdx6-userdebug 3.进入hdx6&#xff0c;修改rk3568_box_32.mk…

行业追踪,2023-08-08

自动复盘 2023-08-08 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

C++ STL string类

目录 一.为什么学习string类 &#xff08;1&#xff09; C语言中的字符串 &#xff08;2&#xff09;标准库里面的string类 二. string类的常用接口说明 &#xff08;1&#xff09;string类对象的常见构造 &#xff08;2&#xff09;string类对象的容量操作 1.size(),le…

2023年中期奶粉行业分析报告(京东数据开放平台)

根据国家统计局和民政部数据公布&#xff0c;2022年中国结婚登记数创造了1980年&#xff08;有数据公布&#xff09;以来的历史新低&#xff0c;共计683.3万对。相较于2013年巅峰时期的数据&#xff0c;2022年全国结婚登记对数已接近“腰斩”。 2023年“520”期间的结婚登记数…

拖拽宫格vue-grid-layout详细应用及案例

文章目录 1、前言2、安装3、属性4、事件5、占位符样式修改6、案例 1、前言 vue-grid-layout是一个适用于vue的拖拽栅格布局库&#xff0c;功能齐全&#xff0c;适用于拖拽高度/宽度自由调节的布局需求&#xff0c;本文将讲述一些常用参数和事件&#xff0c;以及做一个同步拖拽…

[原创]从model-based推导到model-free(到PG+general advantage estimation)

前言 这篇博客很久之前就想做了&#xff0c;一直在拖是因为觉得自己对知识点理解还没有足够的透彻。但是每当去复盘基本概念的时候又很难理清逻辑&#xff0c;所以觉得即便现在半吊子水平&#xff0c;但是也想通过博客记录一下自己肤浅的学习心得&#xff0c;权当是为自己巩固…

metersphere性能压测执行过程

(1) 首先在controller层&#xff0c;通过RunTestPlanRequest接收请求参数 PostMapping("/run")public String run(RequestBody RunTestPlanRequest request) (2) 在PerformanceTestService中的run中进行具体的逻辑处理&#xff0c; 首先根据请求中ID来获取库中存储…

128.【Maven】

Maven仓库 (一)、Maven 简介1.传统项目管理的缺点2.Maven是什么3.Maven的作用 (二)、Maven 的下载与安装1.下载与认识目录2.配置Maven的全局环境 (三)、Maven 的基础概念1.Maven 仓库(1).仓库分类 2. Maven 坐标3.Maven 本地仓库配置(1).改变默认的仓库地址(2).改变远程仓库地址…

SpringWeb项目核心功能总结

SpringWeb项目核心功能总结 文章目录 SpringWeb项目核心功能总结1.浏览器与Java程序的连接&#xff08;个人偏好使用RequestMapping&#xff09;2.参数的传入3.结果的返回请求转发和请求重定向的区别 核心功能用到的注解&#xff1a; RestControllerControllerResponseBodyRequ…

vr禁毒宣传展厅展馆为观众带来了沉浸式的真实体验

毒品是当今社会的一大毒瘤&#xff0c;给人们的生命和家庭带来了极大的伤害&#xff0c;禁毒教育一直是我们必须重视的一项工作。为了更好地宣传禁毒知识&#xff0c;我们不断地探索新的教育方式&#xff0c;其中&#xff0c;VR禁毒体验已经成为了一股新潮流。 三维网上展厅以数…