【探究】信号槽到底能不能有返回值?

【探究】信号槽到底能不能有返回值?

前言

Qt信号槽到底可不可以有返回值呢?问了下身边的同事,有的人说可以,有的人说不可以。在实际项目中,确实没看到过有人使用带返回值的信号槽,可以说存在感很低。平时大家工作也比较忙,所以也没有时间去较真信号槽到底能不能有返回值。今天就一起带大家较真一下,看一看信号槽能否有返回值。如果可以有返回值,那么又有哪些限制导致大家都不用它呢?

提示:本文代码略多,但是都很简单,请耐心阅读。

上代码

新建一个Qt Widgets Application,在Qt为我们生成的主窗口.h文件中,添加信号槽的声明,分别是

  • 信号QString sigCurrentTime(),用于获取当前时间的信号
  • 槽QString slotCurrentTime(),用于获取当前时间的槽

完整代码如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
namespace Ui { class MainWindow; }class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();signals:// 用于获取当前时间的信号QString sigCurrentTime();private slots:// 用于获取当前时间的槽QString slotCurrentTime();private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

在.cpp文件中,建立信号槽连接,实现槽函数,发送信号并打印返回值。完整代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);connect(this, SIGNAL(sigCurrentTime()), this, SLOT(slotCurrentTime()));qDebug() << "Current Time:" << sigCurrentTime();
}MainWindow::~MainWindow()
{delete ui;
}QString MainWindow::slotCurrentTime()
{return QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss");
}

代码很简单,运行结果如下:
请添加图片描述

答案很明确:信号槽可以有返回值。 即槽的返回值会传递给信号,作为信号的返回值返回。
得出上述结论只是第一步。

下面开始我们的第二问:
是否所有情况下,信号槽返回值都可以正常工作呢?

不同机制下的运行情况

在确保信号槽正常连接,并能够成功发送接收的前提下,影响信号槽工作的因素就只有在connect信号槽时指定的、信号槽的连接方式。
我们知道信号槽的连接方式有以下几种:

  • AutoConnection,
  • DirectConnection,
  • QueuedConnection,
  • BlockingQueuedConnection,
  • UniqueConnection

严格来说,最后一个UniqueConnection是用来保证信号槽一对一连接的,从实现机制上并不算是一种连接方式。所以我们依次测试前四种连接方式,得到了不同的结果。

  • AutoConnection

默认连接方式,输出和前面的输出相同。
请添加图片描述

  • DirectConnection

即代码改成:

connect(this, SIGNAL(sigCurrentTime()), this, SLOT(slotCurrentTime()), Qt::DirectConnection);

此种为直接连接方式,相当于函数调用,输出结果为
请添加图片描述
可以看到,返回值可以正常返回。

  • QueuedConnection

即代码改成:

connect(this, SIGNAL(sigCurrentTime()), this, SLOT(slotCurrentTime()), Qt::QueuedConnection);

此种为异步消息方式连接,用于将消息发向具有消息循环的线程,以消息的方式传递信号,信号槽既可以在同一个线程,也可以在不同的线程。这里在主线程进行了测试,输出结果为
请添加图片描述
线程间信号槽返回值测试结果相同。可以看到异步消息方式,信号槽返回值无法工作。

  • BlockingQueuedConnection

此种方式用于多线程环境下,一个线程向另外一个线程发送信号,并阻塞等待槽执行完成。
下面是多线程的测试代码,添加了一个新的QObject子类:ObjectInSubThread,用于在子线程中运行。代码如下(想要直接看结果的同学可直接跳过):

ObjectInSubThread.h头文件

#ifndef OBJECTINSUBTHREAD_H
#define OBJECTINSUBTHREAD_H#include <QObject>class ObjectInSubThread : public QObject
{Q_OBJECT
public:explicit ObjectInSubThread(QObject *parent = nullptr);private slots:// 用于获取当前时间的槽QString slotCurrentTime();
};#endif // OBJECTINSUBTHREAD_H

ObjectInSubThread.cpp实现文件

#include "ObjectInSubThread.h"
#include <QDateTime>ObjectInSubThread::ObjectInSubThread(QObject *parent) : QObject(parent)
{}QString ObjectInSubThread::slotCurrentTime()
{return QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss");
}

同时修改mainwindow类的代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "ObjectInSubThread.h"
#include <QThread>namespace Ui { class MainWindow; }class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();signals:// 用于获取当前时间的信号QString sigCurrentTime();
private:Ui::MainWindow *ui;ObjectInSubThread *m_obj_in_subthread; /* 子线程中的对象 */QThread m_sub_thread; /* 子线程 */
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), m_obj_in_subthread(0)
{ui->setupUi(this);// 创建子线程对象m_obj_in_subthread = new ObjectInSubThread;// 移动到子线程中m_obj_in_subthread->moveToThread(&m_sub_thread);// 启动子线程消息循环m_sub_thread.start();// 建立信号槽连接connect(this, SIGNAL(sigCurrentTime()), m_obj_in_subthread, SLOT(slotCurrentTime()), Qt::BlockingQueuedConnection);qDebug() << "Current Time:" << sigCurrentTime();
}MainWindow::~MainWindow()
{delete ui;m_sub_thread.quit();m_sub_thread.wait();if (m_obj_in_subthread) delete m_obj_in_subthread;
}

输出结果:
请添加图片描述
表明信号槽返回值功能可以正常工作。

综上所述:

从不同的信号槽连接机制的角度看,不管是在多线程还是单线程,只要是异步非阻塞方式连接的信号槽,都无法获取返回值;只要是同步阻塞方式连接的信号槽,都可以获取返回值。
原理上也比较容易理解。非阻塞方式连接的信号槽,信号返回时,槽还没有返回,如何将返回值传递回去呢,逻辑上是行不通的。只有在同步阻塞的情况下,由响应槽先返回,将返回值传递给信号以后,信号再返回,这样便实现了信号槽的返回值功能。

不同使用方式下的运行情况

上面讲解了不同连接机制下的运行情况。在实际使用时,也有一些情况需要考虑。
比如,一个带返回值的信号,连接到多个带相同类型返回值的槽,最后的返回值是什么?
新建Qt Widgets Application测试,下面是测试代码:

mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>namespace Ui { class MainWindow; }class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();signals:// 用于获取当前时间的信号QString sigCurrentTime();private slots:// 用于获取当前时间的槽QString slotCurrentTime1();// 用于获取当前时间的槽QString slotCurrentTime2();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// sigCurrentTime分别连接到槽slotCurrentTime1()和槽slotCurrentTime2()connect(this, SIGNAL(sigCurrentTime()), this, SLOT(slotCurrentTime1()));connect(this, SIGNAL(sigCurrentTime()), this, SLOT(slotCurrentTime2()));qDebug() << "Current Time:" << sigCurrentTime();
}MainWindow::~MainWindow()
{delete ui;
}QString MainWindow::slotCurrentTime1()
{return QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss") + " slotCurrentTime1";
}QString MainWindow::slotCurrentTime2()
{return QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss") + " slotCurrentTime2";
}

如上所示,信号sigCurrentTime分别连接到了槽slotCurrentTime1()和槽slotCurrentTime2()。
输出结果为:
请添加图片描述
可见,最后输出结果只有一个,另外一个结果丢失或被覆盖,这是符合逻辑的,因为返回值只能有一个,最后的结果会覆盖前面的结果。

结语

本文从实现机制角度、应用场景角度对信号槽返回值功能进行了实验和分析,基本涵盖了工作中的各种使用情形,弄清楚了在不同的情况下,信号槽返回值功能的表现情况。一句话总结就是:

只有同步阻塞连接时才能使用信号槽返回值,且不管有几个槽只能有一个返回值。

正是因为信号槽返回值限制太多,所以才几乎没有人使用。但是我们的研究没有白费,通过研究的过程也加深了我们对信号槽机制的理解。

关于信号槽,有太多话题可以聊,后面会推出更多相关文章,敬请关注!


本文由公众号“Qt未来工程师”原创首发。

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

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

相关文章

【转】第01课:生活中的监听模式——一坑爹的热水器

用程序来模拟生活从剧情中思考监听模式 监听模式监听模式的模型抽象 代码框架类图基于框架的实现模型说明 设计要点推模型和拉模型应用场景 【故事剧情】 刚刚大学毕业的 Tony 只身来到北京这个硕大的城市&#xff0c;开始了北漂的生活。但刚刚毕业的他身无绝技、包无分文&…

【经验】Qt项目开发必备工具

在实际的项目中&#xff0c;除了需要掌握Qt开发框架本身&#xff0c;还需要掌握一些开发工具。这些工具能起到事半功倍的效果&#xff0c;甚至某些工具是开发不可或缺的。下面笔者就介绍一些常用的开发工具的用法及下载地址&#xff0c;希望对缺少实际项目经验的同学提供一些参…

【转】TCP/IP协议--TCP的超时和重传

TCP是可靠传输。可靠之一体现在收到数据后&#xff0c;返回去一个确认。但是不能完全避免的是&#xff0c;数据和确认都可能丢失。解决这个办法就是&#xff0c;提供一个发送的重传定时器&#xff1a;如果定时器溢出时还没收到确认&#xff0c;它就重传这个报文段。 想法是完美…

mysql集群方案对比_MySQL云原生方案在携程开发测试场景中的实践

一、背景与使用场景随着Kubernetes平台在容器云计算领域的一统天下&#xff0c;云原生 (Cloud Native) 一词也被提的越来越频繁。各类应用纷纷走上了容器化、云原生化的道路&#xff0c;无状态服务应用在Kubernetes平台上的运行&#xff0c;已经得到了大规模生产级别的实践认可…

vb.net datagridview数据批量导入sql_【自学C#】|| 笔记 44 ComboBox:组合框控件数据绑定...

一、ComboBox&#xff1a;组合框控件数据绑定在 Windows 应用程序中很多控件都提供了 DataSource 属性&#xff0c;并将 DataSet 或 DataTable 的值直接赋给该属性&#xff0c;这样在控件中即可显示从数据库中查询出来的数据。 常用的数据绑定控件有文本框(TextBox)、标签(L…

【转】C#Socket编程详解(一)TCP与UDP简介

一、TCP与UDP 1、TCP 1.1 定义 TCP&#xff08;TransmissionControl Protocol&#xff09;传输控制协议。 是一种可靠的、面向连接的协议&#xff08;eg:打电话&#xff09;、传输效率低全双工通信&#xff08;发送缓存&接收缓存&#xff09;、面向字节流。使用TCP的应…

【精华】掌握Qt调试技术

前言 软件调试&#xff0c;是开发过程中必备的技能。通过调试可以发现软件存在的bug&#xff0c;即缺陷。调试可以帮助开发者窥探到软件运行过程中的详细状态&#xff0c;从而为消除bug提供重要信息。调试的英文是debug&#xff0c;前面的de在英文中表示“反对”&#xff0c;“…

ps海报合成教程_如何利用PS制作海报?详细教程来了!

今天能学长给大家带来一套利用PS做【月满中秋】海报的教程。福利干货到&#xff0c;请大家接住&#xff01;话不多说&#xff0c;直接上教程【月满中秋-第一课】月满中秋-海报制作教程https://www.zhihu.com/video/1187797197951918080为了方便大家阅读&#xff0c;本篇文章特地…

【转】WebSocket详解(一):初步认识WebSocket技术

1、前言 HTML5规范在传统的web交互基础上为我们带来了众多的新特性&#xff0c;随着web技术被广泛用于web APP的开发&#xff0c;这些新特性得以推广和使用&#xff0c;而websocket作为一种新的web通信技术具有巨大意义。 本文将带您认识WebSocket。也可查看本文的下篇&#x…

【Qt调试技巧】Profile配置使用及一些坑

介绍 不知从哪个版本起&#xff0c;Qt Creator中的构建配置中&#xff0c;增加了一种新型配置&#xff0c;名叫“Profile”&#xff0c;如下图所示&#xff1a; 官方对Profile的描述是&#xff1a;Profile是介于Debug和Release中间的一种配置。具体是什么意思呢&#xff1f;…

【转】带你玩转Visual Studio——03.带你了解VC++各种类型的工程

上一篇文章带你玩转Visual Studio——带你新建一个工程一文中提到新建一个工程时会有很多的工程类型(图1)&#xff0c;现在将简单介绍各种类型工程的含义和主要用途。由于这里包含的工程类型太多&#xff0c;有很多本人也没有接触过&#xff0c;有些可能理解的不太对的地方还请…

如何调整金格电子章服务器印章_重磅!公安部再度认可电子签名、电子印章法律效力!...

近日&#xff0c;公安部发布《关于修改〈公安机关办理刑事案件程序规定〉的决定》&#xff0c;对《公安机关办理刑事案件程序规定》&#xff08;以下简称规定&#xff09;进行了全面修改完善&#xff0c;并将于9月1日起施行。修改后的规定共14章388条。其中&#xff0c;新增的第…

【转】带你玩转Visual Studio——04.带你高效开发

上一篇文章带你玩转Visual Studio——带你了解VC各种类型的工程一文中讲了各种类型VC工程的主要功能和用途。现在将带你一起快速开发c程序。 有过Java开发经验的人都知道Java的常用开发工具(如Eclipse、Intellij IDEA等)都有非常强大的关键字高亮、智能提示、快速追踪等的功能…

【信号与线性系统】知识点与学习攻略

知识点理解 关于正交分解可以看这个视频&#xff1a; https://www.bilibili.com/video/BV1qV411C7u6/ 记住两个完备正交函数集&#xff1a; 一个是正余弦三角函数&#xff0c;非零不同频率项乘积为0&#xff0c;非零同频率项乘积积分为T/2&#xff0c;零频率项乘积积分为T。 一…

2020-12-19

逆变&#xff08;contravariant&#xff09;与协变&#xff08;covariant&#xff09;是C#4新增的概念&#xff0c;许多书籍和博客都有讲解&#xff0c;我觉得都没有把它们讲清楚&#xff0c;搞明白了它们&#xff0c;可以更准确地去定义泛型委托和接口&#xff0c;这里我尝试画…

微软模拟飞行10厦门航空涂装_《微软飞行模拟器》多人游戏模式演示:可组队飞行...

IT之家3月29日消息 《微软飞行模拟器》(Flight Simulator)是2020年最受期待的游戏之一&#xff0c;开发商Asobo Studio现在分享了一段新的视频&#xff0c;详细介绍了《微软飞行模拟器》的多人游戏模式。《微软飞行模拟器》游戏的主模式将看到所有玩家在同一个世界中一起玩。微…

【转】UDP协议格式以及在java中的使用

UDP协议格式以及在java中的使用 UDP是面向无连接的通讯协议&#xff0c;由于通讯不需要连接&#xff0c;所以可以实现广播发送。UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象&#xff0c;实际应用中要求程序员编程验证。 UDP适用于…

python网页填表教程_PythonSpot 中文系列教程 · 翻译完成

原文&#xff1a;PythonSpot Python Tutorials 协议&#xff1a;CC BY-NC-SA 4.0 欢迎任何人参与和完善&#xff1a;一个人可以走的很快&#xff0c;但是一群人却可以走的更远。在线阅读ApacheCN 学习资源目录PythonSpot 中文系列教程初学者 介绍Python 字符串字符串&#xff0…

【转】TCP/IP协议到底在讲什么?【乐搏TestPro】

用比喻和漫画给有需要的小伙伴解释下IP、TCP捎带题一下各种协议与HTTP协议的关系&#xff1b; 目录&#xff1a; 负责传输的IP协议 确保可靠性的TCP协议 各种协议与HTTP协议的关系 一、负责传输的IP协议 按照层次分&#xff0c;IP&#xff08;全称&#xff1a;Internet Prot…

Qt中标绘功能的实现方法对比

使用Qt开发桌面程序&#xff0c;经常会有标绘的需求&#xff0c;一般有以下几点&#xff1a; 新建&#xff1a;圆、矩形、椭圆、文字标注&#xff0c;插入图像等&#xff1b;编辑&#xff1a;指对已标绘内容的属性编辑修改功能&#xff1b;删除&#xff1a;指对已标绘内容的删…