Qt中带返回值的信号发射(使用QMetaObject::invokeMethod)

2023-05-16

一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值。那么如果我们发出这个信号想获取一个返回值怎么办呢?

两个办法:1.通过出参形式返回,引用或者指针的方式带回;比如emit sig(int& i)或者emit sig(void* pointer),但是这个方法有一个弊端,稍后介绍第二种方式会提醒。

2.通过qt自带的invoke机制调用:参考文档对QMetaObject::invokeMethod的说明:Invokes the member (a signal or a slot name) on the object obj.也就是说回调是可以回调信号或者槽的。一般来说,我们使用invokeMethod是在子线程需要调度UI操作的时候,因为UI操作只能在主线程中使用(否则会出现未定义错误)。大部分情况下,我们把UI操作封装在一个槽里,用回调方式来调度。同样信号也可以用这种方式,但是有几点需要注意的是,1.调用回调的连接方式:如果信号和连接槽在一个线程内,那么必须用Qt::DirectConnection或者Qt::AutoConnection,这样的话,保证信号回调后,线程会等待信号连接槽执行完毕,才可能取到我们需要的返回值;如果使用了Qt::QueuedConnection,那么信号只是负责把事件交给事件队列,然后马上做出返回,这样,是否有返回值就无法确定了(这也就是第一个方法的弊端).如果信号和槽在两个线程中,那么首先肯定不能使用Qt::DirectConnection,除非你很清楚连接槽的动作是否保证了线程安全。但根据第一条的说明,也不能使用Qt::QueuedConnection。不过还好qt提供了一个额外的连接方式就是Qt::BlockingQueuedConnection,这个连接方式会阻塞住发射信号的线程一直等到队列连接槽返回后,才会恢复阻塞,这样就可以保证我们能拿到真正的返回值。(但是使用这种方式需要你清楚的知道,发射线程是否允许阻塞和连接槽是否对这个阻塞线程有什么特别的操作,一般来说,如果这个线程并不是由你自己控制的话,不要随便尝试去阻塞别人的线程,因为你并不清楚别人线程的执行逻辑)

调用方式大致代码如下bool bReturn; QMetaObject::invokeMethod(&object, "sig", Qt::DirectConnection/*Qt::QueuedConnection*/, Q_RETURN_ARG(bool, bReturn), Q_ARG(int, i));

/************************

QT 信号槽返回值

一、方法
获取信号槽返回值的方法有三种:
(1)通过形参的方式,传递引用或者指针。(未写例子)

(2)直接在信号发出位置获取返回值。(下面有例子)

(3)通过QMetaObject::invokeMethod方法。(具体使用可以参考QT的帮助文档或者看下面的代码实例)

二、代码
#ifndef WRITETHREAD_H
#define WRITETHREAD_H
 
#include <QObject>
 
class WriteThread : public QObject
{
    Q_OBJECT
public:
    WriteThread(QObject *parent = nullptr);
 
public slots:
    QString slotWrite(QString str);
 
signals:
 
};
 
#endif // WRITETHREAD_H
#include "writethread.h"
#include <QDebug>
#include <QDateTime>
#include <QThread>
WriteThread::WriteThread(QObject *parent) : QObject(parent)
{
 
}
 
QString WriteThread::slotWrite(QString str)
{
    qDebug()<<"执行了slotWrite 子线程id:"<<QThread::currentThreadId();
    QThread::sleep(3);
    QString date = "函数返回时间:"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    return str + "\n" + date + "\n";
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "writethread.h"
#include <QThread>
 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
 
signals:
    QString signalWrite(QString str);
 
 
private slots:
    void on_pushButton_clicked();
 
    void on_pushButton_2_clicked();
 
private:
    Ui::MainWindow *ui;
 
    QThread *m_pThread;
    WriteThread *m_pWriteThread;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDebug>
#include<QDateTime>
 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    qDebug()<<"主线程id:"<<QThread::currentThreadId();
    m_pThread = new QThread;
    m_pWriteThread = new WriteThread;
    m_pWriteThread->moveToThread(m_pThread);
    connect(this,&MainWindow::signalWrite,m_pWriteThread,&WriteThread::slotWrite,Qt::BlockingQueuedConnection);
    m_pThread->start();
}
 
MainWindow::~MainWindow()
{
    delete ui;
 
    m_pThread->quit();
    m_pThread->wait();
    delete m_pThread;
    m_pThread = NULL;
}
 
//写值 方法1:直接获取返回值
void MainWindow::on_pushButton_clicked()
{
    qDebug()<<"点击了写值按钮";
    QString str = "信号发出时间:"+ QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    qDebug()<<"信号发出了";
    QString ret = signalWrite(str);
    qDebug()<<"返回值为:"<<ret;
    ui->textEdit->append(ret);
}
 
//写值 方法2:QMetaObject::invokeMethod
void MainWindow::on_pushButton_2_clicked()
{
    qDebug()<<"点击了写值按钮";
    QString str = "信号发出时间:"+ QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    QString ret;
    QMetaObject::invokeMethod(m_pWriteThread, "slotWrite", Qt::BlockingQueuedConnection,
                              Q_RETURN_ARG(QString, ret),
                              Q_ARG(QString, str));
    qDebug()<<"返回值为:"<<ret;
    ui->textEdit->append(ret);
}
ui界面

  结果

三、补充    
        ①信号发送者和接受者在同一个线程,也就是直接连接,参数为Qt::DirectConnection。此时为同步调用,信号发送之后会等待槽函数的执行,可接收到返回值。

       ②当信号发送者和接受者不在同一个线程,也就是队列连接,参数为Qt::QueuedConnection时。此时为异步调用,信号发出之后,把事件交给事件队列,不等待槽函数的执行直接返回,不能接收到返回值。

       ③当信号的发送者和接受者不在同一个线程时,可以使用Qt::BlockingQueuedConnection参数,该参数会阻塞信号发送者所在线程,直到槽函数执行完成之后才会往下执行,可以接收到返回值。需要注意:如果信号的发送者和接受者在一个线程,使用该参数会造成程序死锁。


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt中带返回值的信号发射(使用QMetaObject::invokeMethod) 的相关文章

  • 类对象的内存和堆空间的内存及初始化详解

    对象的内存 对象的内存可以存在于 3 种地方 xff1a 全局区 xff08 数据段 xff09 xff1a 全局变量栈空间 xff1a 函数里面的局部变量堆空间 xff1a 动态申请内存 xff08 malloc new等 xff09 文
  • C++内存空间管理

    1 C 43 43 内存机制 1 栈 Stack xff0c 函数中的局部变量 xff0c 由编译器负责分配释放 xff0c 函数结束 xff0c 变量释放 2 堆 Heap xff0c 通过new 申请的内存 xff0c 由delete或
  • Qt中跨线程下信号和槽的使用方法

    connect用于连接qt的信号和槽 xff0c 在qt编程过程中不可或缺 它其实有第五个参数 xff0c 只是一般使用默认值 xff0c 在满足某些特殊需求的时候可能需要手动设置 Qt AutoConnection xff1a 默认值 x
  • Qt 中开启线程的多种方式小结

    简介1 继承 QThread 重写 run 函数2 继承 QObject 调用 moveToThread3 继承 QRunnable 重新 run 函数 xff0c 结合 QThreadPool 实现线程池4 使用 C 43 43 11 中
  • Qt中exec函数的作用

    Qt中的exec 方法到处可见 xff0c 例如 xff1a QCoreApplicaton exec QApplication exec QDialog exec QThread exec QMenu exec 那么 xff0c 这些ex
  • 在Qt中使用全局变量的两种方式,及出现无法解析的命令的问题

    很多小伙伴在Qt编程时 xff0c 不会使用全局变量 xff0c 其实基本有两种方式来定义使用全局变量 xff0c 第一种是根据c c 43 43 的extern来进行多文件的使用 xff0c 第二种方法就是把全局变量放在类中 xff0c
  • Qt中信号槽形参值传递,引用传递,指针传递的实例及总结

    在同一个线程中 当信号和槽都在同一个线程中时 xff0c 值传递参数和引用传递参数有区别 xff1a 值传递会复制对象 xff1b xff08 测试时 xff0c 打印传递前后的地址不同 xff09 引用传递不会复制对象 xff1b xff
  • vnc远程连接,5个步骤教你如何轻松实现vnc远程连接

    当我们在进行vnc远程连接时 xff0c 往往找不到有用的工具来支撑我们的工作 那当我们在进行vnc远程连接时 xff0c 有什么工具能让我们快速实现vnc远程连接呢 xff1f iis7服务器管理工具 如图 xff1a IIS7服务器管理
  • 关于qt信号槽传指针与释放指针

    今天 xff0c 意外发现qt中信号槽传指针的方式进行时 xff0c 会发生释放不掉指针所分配的空间的情况 定义一个信号 void emit showTime Data 槽 void slot showTime Data 在发出信号之前动态
  • Qt-信号和槽函数传递自定义参数前需注册自定义数据类型

    Qt 信号和槽函数参数只能是基于 Qt 的基础类型的 xff0c 比如 QString int bool 等 xff0c 如果想传递自定义类型默认情况下是行不通的 要想在 Qt 的信号和槽函数之间传递自定义类型 xff0c 可以先将自己的自
  • Qt 设置窗口背景图片的几种方法实例

    1 在paintEvent事件中绘制图片 void Widget paintEvent QPaintEvent ev QPainter painter this painter drawPixmap rect QPixmap 34 bg j
  • Qt事件处理的几种方式

    Qt提供了5种事件处理和事件过滤的方法 xff1a 1 重写事件处理器函数 这是大部分情况最常用的一种 xff0c 如重写 paintEvent mousePressEvent keyPressEvent 等事件处理器虚函数 2 重写 QO
  • QT中添加图片资源的方法

    1 在ui设计界面中添加label xff0c 用于显示图片 2 添加QT资源文件 往项目中添加新文件 xff0c 选择QT分类中的资源文件 xff0c 名称为 34 myImage 34 其他选项默认 3 添加资源 在项目目录下新建文件夹
  • Q_OBJECT的作用

    只有继承了QObject类的类 xff0c 才具有信号槽的能力 所以 xff0c 为了使用信号槽 xff0c 必须继承QObject 凡是QObject类 xff08 不管是直接子类还是间接子类 xff09 xff0c 都应该在第一行代码写
  • Qt编写自定义控件及插件的使用

    在使用Qt Designer设计窗体界面时 xff0c 我们可以使用Widget Box里的窗体控件非常方便的绘制界面 xff0c 比如拖进去一个按钮 xff0c 一个文本编辑器等 虽然Qt Designer里的控件可以满足我们大部分的需求
  • QT中窗口去掉最大化最小化关闭按钮及菜单的方法

    在QT界面开发过程中 xff0c 有的时候需要隐藏最大化最小化甚至是关闭按钮 xff0c 以排除用户的操作系统无定义 xff0c 让程序流向混乱现总结如下 xff1a 1 Qt的QDialog去掉最大化和最小化以及关闭按钮 xff1a 在构
  • Qt创建右键菜单的方法

    函数 所有派生自QWidget的控件 xff0c 若实现在其上右键单击弹出菜单 xff0c 需要设置该控件的上下文菜单策略函数为setContextMenuPolicy Qt CustomContextMenu xff0c 设置该策略后当用
  • QT 中实现QLabel的点击事件(重写QLabel)

    默认情况下 xff0c QLabel是不支持点击事件的 xff0c 要实现QLabel的点击事件 xff0c 一般有两种方式 xff1a 1 继承QLabel xff0c 重写鼠标点击事件 xff0c 通过发送信号与父窗体实现通讯 Clic
  • flashfxp连接失败,flashfxp连接失败怎么办

    FlashFXP是一款功能强大的FXP FTP软件 xff0c 允许你从任何ftp服务器直接传输文件到你的本地硬盘 xff0c 或者在两个FTP站点之间传输文件 xff0c 即站点到站点传输 xff0c 而无须经过自己的计算机 听起来是不是
  • Qt 模态窗口和非模态窗口

    项目中要用到非模态窗口 xff0c 程序一开始弹出一个主窗口来 xff0c 点击一个按钮的时候弹出一个非模态窗口 xff0c 虽然是一个比较简单的需求 xff0c 但是在实现的过程中有各种问题 列一下自己遇到的问题并且说一下自己的解决方法

随机推荐