首页 > 其他分享 >Qt子线程中使用UI线程

Qt子线程中使用UI线程

时间:2022-12-13 16:56:32浏览次数:52  
标签:DispatchMainThread Qt timer callback dispatchToMainThread UI 线程 MainWindow

Qt 子线程中使用UI线程

方案起源

最近做了一个Excel保存图表的项目,因为不能直接用Excel的图表(会直接暴露计算数据),所以采用的是QCharts生成的表格,但是QCharts的问题是 调用QChartView::setChart接口之后,会出现不在同一个线程的问题,简单来说就是必须在主(UI)线程才能进行setChart操作。

如何方便的在子线程中调用主线程,就成为了要解决的主要问题。

搜寻了很多方案,对MainWindow的耦合很严重,况且我也不需要访问MainWindow的UI控件,我只是借用主线程保存一下图表而已。

找了很久,找到一个Stack Overflow上面的方案。

Stack Overflow 方案

#include <functional>

void dispatchToMainThread(std::function<void()> callback)
{
    QTimer* timer = new QTimer();
    timer->moveToThread(qApp->thread());
    timer->setSingleShot(true);
    QObject::connect(timer, &QTimer::timeout, [=]()
    {        
        callback();
        timer->deleteLater();
    });
    QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}

采用了这个方案,貌似很完美的解决了问题,只需要将此方案,新建一个类,放置dispatchToMainThread接口,然后利用lambda函数,传递callback即可。如下所示:

A a;
a.dispatchToMainThread( [&]{
    func(x);
});

但是采用这种方案最大的问题在于,timer->deletelater()是让系统去管理timer何时释放资源,但是如果线程比较多的话,timer根本就不会delete,一直处在activate状态,在 上面调用dispatchToMainThread之后,如果函数体结束了,就会造成资源释放的问题,导致软件崩溃。

想到了一个方法,就是在invokemethod后面加Qt::BlockingQueuedConnection,然后直接调用QTimer::destroy,但是这样也会崩溃,因为系统会判断,QTimer未运行结束,就强制结束。

索性最后想到一个完美的解决方案,一定程度上减少了对MainWindow的依赖。

我的解决方案

  • 在MainWindow中

    建立MainWindow的单例模式,然后添加如下方法

    void MainWindow::dispatch2MainThread(std::function<void ()> callback)
    {
        callback();
    }
    
  • 新建DispatchMainTherad类,代码如下

    头文件

    #include <functional>
    #include <QObject>
    
    class DispatchMainThread
            : public QObject
    {
        Q_OBJECT
    public:
        static DispatchMainThread *instance();
    protected:
        DispatchMainThread();
    public:
        ~DispatchMainThread();
    signals:
        void dispatch2MainThread(std::function<void()> callback);
    
    public:
        void dispatchToMainThread(std::function<void()> callback);
    
    private:
        static DispatchMainThread *self;
    };
    

    源文件

    #include "dispatchmainthread.h"
    #include "mainwindow.h"
    #include "mutex.h"
    
    DispatchMainThread *DispatchMainThread::self = nullptr;
    DispatchMainThread *DispatchMainThread::instance()
    {
        static std::once_flag onceFlag;
    
        std::call_once(onceFlag, [&]
        {
            self = new DispatchMainThread();
            QObject::connect(self, &DispatchMainThread::dispatch2MainThread, MainWindow::instance(), &MainWindow::dispatch2MainThread,
                             Qt::BlockingQueuedConnection);
        });
    
        return self;
    }
    
    DispatchMainThread::DispatchMainThread()
        : QObject()
    {
    
    }
    
    DispatchMainThread::~DispatchMainThread()
    {
        if(!self)
        {
          delete self;
        }
    }
    
    void DispatchMainThread::dispatchToMainThread(std::function<void ()> callback)
    {
        emit dispatch2MainThread(callback);
    }
    
  • 使用部分代码

    auto dis = DispatchMainThread::instance;
    dis->dispatchToMainThread([&](){yourFunction();});
    

说明

因为是粗略的代码,所以删除了部分细节,优化就看读者自己的操作了,代码直接使用的问题,请自己Debug,思路已经很详细了。

标签:DispatchMainThread,Qt,timer,callback,dispatchToMainThread,UI,线程,MainWindow
From: https://www.cnblogs.com/ligiggy/p/16979261.html

相关文章

  • UI自动化中上传与唤醒弹窗
    本篇想谈的是在ui自动化中对上传的一些理解,干货满满。一.是否有必要唤醒弹窗以selenium为代表的库在进行文件上传时,是可以直接对输入框“发送”文件的,其send_keys(......
  • spring mvc环境之UI到控制器的自定义类型转换(十三)
     spring其实有默认的类型转换,比如前端表单提交数字的字符串,在控制器可接收为int或string都是没有错的.另外控制器也可以把前端数据接收为一个对象.即使spring为我们考虑......
  • 企业数据自助分析的基础:用好瓴羊Quick BI 数据填报
    日前,行业咨询机构赛迪顾问发布了《2021-2022年中国企业级应用软件市场研究年度报告》。《报告》显示,2021年中国企业级应用软件市场快速回升,市场规模突破606亿元,增速高达16.2......
  • <三>线程间同步通信-生产者消费者模型
    多线程编程两个问题1:线程互斥问题竞态条件->临界区代码段->原子操作->互斥锁mutex2:线程间的同步通信生产者,消费者线程模型#include<iostream>#include<queue>#......
  • c++11 线程池--鸿蒙OS
    一个你应该学习的线程池说明原理:线程+优先级队列.源码没有涉及STL,没有复杂高深的语法,安全性做得很好:queue的安全使用方式top和pop以及empty的判断都是使用了std::......
  • [ Linux ] 一篇带你理解Linux下线程概念
    1.Linux线程的概念1.1什么是线程在之前我们谈过Linux的进程,每一个进程都有自己的PCB,和自己的进程地址空间。地址空间和物理内存通过页表建立映射。那么现在我要创建一个新的......
  • 【Unity Shader】Special Effects(二)BorderFlow 边框流动(UI)
    更新日期:2021年8月23日。Github源码:​​​[点我获取源码]​​索引​​BorderFlow边框流动​​​​思路分析​​​​流光区域​​​​流光区域的中心点​​​​流光区域的......
  • Unity UGUI图文混排源码(一)
    我从一开始想到的图文混排的概念都是通过文字间的空隙去粘贴一张图片,这样确定图片前面文字的最后一个位置变成了最主要的参数,接下来就给出两种解决方案首先,先发UGUI源码的一......
  • Unity UGUI基础之Text
    Text作为UGUI最基础的控件以及最常用的控件,它在项目中的应用绝对可以算是最多的,任何一个UI界面可以说都离不开它,它的基本属性如下:一、recttransform组件:recttransform(矩形......
  • Unity UGUI实现图文混排
    目前在unity实现图文混排的好像都是通过自定义字体然后在文本获取字符的位置,用图片替换掉图片标签,这样对于支持英文来说,并没有什么影响。然后对于中文来说就是一个相当麻烦......