【探究】信号槽到底能不能有返回值?
【探究】信号槽到底能不能有返回值?
前言
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_OBJECT public: 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_OBJECT public: 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_OBJECT public: 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未来工程师”原创首发。
本文来自博客园,作者:撬动未来的支点,转载请注明原文链接:https://www.cnblogs.com/pivotfuture/p/16297347.html
CSDN:撬动未来的支点,公众号:Qt未来工程师,网站:www.qtfuture.cn
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!