Qt 跨UI线程的数据交换和信号-槽调用实现方案汇总

一、目录

 转载1: http://my.oschina.net/fanhuazi/blog/737224?ref=myread 点击打开链接

 转载2: http://www.qtcn.org/bbs/read-htm-tid-60505-ds-1-page-1.html#172183 点击打开链接


二、内容

由于以下两篇转载文章都使用了C++11 新特性“lamda表达式”,为了方便同仁阅读以下内容,在此引用一片文章对“C++11 lamda表达式”做一个简要介绍:

“C++11 lamda表达式”  ,点击此链接先了解C++11新增语法,对后面内容的阅读会有帮助。


转载1: http://my.oschina.net/fanhuazi/blog/737224?ref=myread 点击打开链接

在Qt中将函数发送到主线程执行

……(省略部分内容,完成内容请参看上面的原文链接)数据共享的问题,试想“后台线程(非UI线程)中的数据如何能够被前台(UI线程)所使用,而且前台后台不一定在一个类里面?把数据打包通过信号传给前台?”想想就是很麻烦的事情,难道每个这样的需求场合都要做一遍这样的事情吗?感谢时间,因为时间穿过2011年,C++的新标准已经完美的解决了这个问题,那就是函数对象。
Qt的4.8.6版本所使用的mingw4.9.2版本是支持C++11的,如果你用的是老掉牙的rhel5系统,则需要升级编译器了,因为C++11要在GCC 4.5以上的版本中才会支持。
首先我们定义一个类:FunctionTransfer(函数大挪移),这个类继承自QObject,并使用Q_OBJECT标签来使用信号槽机制。代码中的“std::tr1::function<void()>”就是C++标准库中大名鼎鼎的函数对象。

class FunctionTransfer : public QObject

{
    Q_OBJECT

public:

    ///@brief 构造函数

    explicit FunctionTransfer(QObject *parent = 0);

public:

    ///@brief 制定函数f在main中执行

static void execinmain(std::tr1::function<void()> f);

signals:

    ///@brief 在别的线程有函数对象传来

    void comming(std::tr1::function<void()> f);

public slots:

    ///@brief 执行函数对象

    void exec(std::tr1::function<void()> f);
};


然后是源文件:
//在全局数据区实例化一个FunctionTransfer的实例,该实例所在的县城就是主线程。

FunctionTransfer main_thread_forward;
void FunctionTransfer::execinmain(std::tr1::function<void()> f)
{
    main_thread_forward.exec(f);
}
 
FunctionTransfer::FunctionTransfer(QObject *parent) :
    QObject(parent)
{
    connect(this,SIGNAL(comming(std::tr1::function<void()>)),this,SLOT(exec(std::tr1::function<void()>)),Qt::BlockingQueuedConnection);
}
 
 
void FunctionTransfer::exec(std::tr1::function<void()> f)
{
    if(Gt::isMainThread())
    {
        f();
    }
    else
    {
        emit this->comming(f);
    }
}

非常简单的逻辑,如果在主线程就执行,如果不是在主线程就发给主线程,主线程接到之后就执行。
类有了,接下来考虑实用的场合,比如有一个类 A,A有个方法f不能再后台执行,需要跑到前台,怎么办呢,上代码:
FunctionTransfer::execinmain([this](){this->f();});
作为参数的lamda表达式捕获了类A的this指针,然后转换为C++的函数对象,然后跑到前台去执行了,执行完成后才会返回,是不是灰常简洁。



转载2:http://www.qtcn.org/bbs/read-htm-tid-60505-ds-1-page-1.html#172183 点击打开链接

#pragma once
#include <qthread.h>
#include <functional>

class QIoService : QObject
{
public:
    QIoService(bool startinthread)
    {
        if(startinthread)
        {
            worker=new QThread(NULL);
            worker->start();
            this->moveToThread(worker);
        }
        else
        {
            //this object is created in create thread!!!
        }
    }

    void post(std::function<void()> func);
    void send(std::function<void()> func);
    
    void post(std::function<void()> func,int ms);
    void send(std::function<void()> func,int ms);
    
    virtual bool event ( QEvent * e);
    
protected:
    QThread *worker;
};


//this should run in mainthread
extern QIoService *main_ioservice;



#include "stdafx.h"
#include "qioservice.h"
#include <qapplication.h>
#include <qtconcurrentrun.h>

QIoService *main_ioservice=NULL;

class FunctionEvent : public QEvent
{
public:
    static const QEvent::Type myType = static_cast<QEvent::Type>(2000);
    FunctionEvent(std::function<void()> f)
        :QEvent(myType)
    {
        func=f;
    }
    
    ~FunctionEvent()
    {
        //这个他会自动删除
    }

    std::function<void()> func;
    
};

void QIoService::post(std::function<void()> func)
{
    QApplication::instance()->postEvent(this,new FunctionEvent(func));
}

void QIoService::send(std::function<void()> func)
{
     QApplication::instance()->sendEvent(this,new FunctionEvent(func));
}

void QIoService::post(std::function<void()> func,int ms)
{
    auto lam = [&]()
    {
        QThread::currentThread()->wait(ms);
        post(func);
    };
    QtConcurrent::run(lam);
}

void QIoService::send(std::function<void()> func,int ms)
{
    auto lam = [&]()
    {
        QThread::currentThread()->wait(ms);
        send(func);
    };
    QtConcurrent::run(lam);  
}

bool QIoService::event ( QEvent * e)
{
    if(e->type()==FunctionEvent::myType)
    {
        FunctionEvent *fe=(FunctionEvent *)e;
        fe->func();
        return true;
        //这个他会自动删除,不用我们自己手工delete
    }
    return false;
}
注解:

//比如你在另外一个线程,你收到数据,想修改界面。就弄个全局变量
QIoService g_ui_ios(false);

//你只要
g_ui_ios.send([你的变量]
{
   //修改界面数据,这个会在主线程执行
});

//如果你是想写个任务队列,
QIoService g_worker_ios(true);

//你要把某段事情丢到其他线程执行,就
g_worker_ios.send([]
{
  //这段会在其他线程执行。
  如果执行完了,又想在主线程执行某段,这里可以继续
  //g_ui_ios.send([]
  {
    //这段会在主线程执行
  });
});


三、更新

2016年8月27日 第一次更新

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值