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++标准库中大名鼎鼎的函数对象。

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. class FunctionTransfer : public QObject  
  2.   
  3. {  
  4.     Q_OBJECT  
  5.   
  6. public:  
  7.   
  8.     ///@brief 构造函数  
  9.   
  10.     explicit FunctionTransfer(QObject *parent = 0);  
  11.   
  12. public:  
  13.   
  14.     ///@brief 制定函数f在main中执行  
  15.   
  16. static void execinmain(std::tr1::function<void()> f);  
  17.   
  18. signals:  
  19.   
  20.     ///@brief 在别的线程有函数对象传来  
  21.   
  22.     void comming(std::tr1::function<void()> f);  
  23.   
  24. public slots:  
  25.   
  26.     ///@brief 执行函数对象  
  27.   
  28.     void exec(std::tr1::function<void()> f);  
  29. };  

然后是源文件:

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //在全局数据区实例化一个FunctionTransfer的实例,该实例所在的县城就是主线程。  
  2.   
  3. FunctionTransfer main_thread_forward;  
  4. void FunctionTransfer::execinmain(std::tr1::function<void()> f)  
  5. {  
  6.     main_thread_forward.exec(f);  
  7. }  
  8.    
  9. FunctionTransfer::FunctionTransfer(QObject *parent) :  
  10.     QObject(parent)  
  11. {  
  12.     connect(this,SIGNAL(comming(std::tr1::function<void()>)),this,SLOT(exec(std::tr1::function<void()>)),Qt::BlockingQueuedConnection);  
  13. }  
  14.    
  15.    
  16. void FunctionTransfer::exec(std::tr1::function<void()> f)  
  17. {  
  18.     if(Gt::isMainThread())  
  19.     {  
  20.         f();  
  21.     }  
  22.     else  
  23.     {  
  24.         emit this->comming(f);  
  25.     }  
  26. }  


非常简单的逻辑,如果在主线程就执行,如果不是在主线程就发给主线程,主线程接到之后就执行。
类有了,接下来考虑实用的场合,比如有一个类 A,A有个方法f不能再后台执行,需要跑到前台,怎么办呢,上代码:

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. 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 点击打开链接

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2. #include <qthread.h>  
  3. #include <functional>  
  4.   
  5. class QIoService : QObject  
  6. {  
  7. public:  
  8.     QIoService(bool startinthread)  
  9.     {  
  10.         if(startinthread)  
  11.         {  
  12.             worker=new QThread(NULL);  
  13.             worker->start();  
  14.             this->moveToThread(worker);  
  15.         }  
  16.         else  
  17.         {  
  18.             //this object is created in create thread!!!  
  19.         }  
  20.     }  
  21.   
  22.     void post(std::function<void()> func);  
  23.     void send(std::function<void()> func);  
  24.       
  25.     void post(std::function<void()> func,int ms);  
  26.     void send(std::function<void()> func,int ms);  
  27.       
  28.     virtual bool event ( QEvent * e);  
  29.       
  30. protected:  
  31.     QThread *worker;  
  32. };  
  33.   
  34.   
  35. //this should run in mainthread  
  36. extern QIoService *main_ioservice;  
  37.   
  38.   
  39.   
  40. #include "stdafx.h"  
  41. #include "qioservice.h"  
  42. #include <qapplication.h>  
  43. #include <qtconcurrentrun.h>  
  44.   
  45. QIoService *main_ioservice=NULL;  
  46.   
  47. class FunctionEvent : public QEvent  
  48. {  
  49. public:  
  50.     static const QEvent::Type myType = static_cast<QEvent::Type>(2000);  
  51.     FunctionEvent(std::function<void()> f)  
  52.         :QEvent(myType)  
  53.     {  
  54.         func=f;  
  55.     }  
  56.       
  57.     ~FunctionEvent()  
  58.     {  
  59.         //这个他会自动删除  
  60.     }  
  61.   
  62.     std::function<void()> func;  
  63.       
  64. };  
  65.   
  66. void QIoService::post(std::function<void()> func)  
  67. {  
  68.     QApplication::instance()->postEvent(this,new FunctionEvent(func));  
  69. }  
  70.   
  71. void QIoService::send(std::function<void()> func)  
  72. {  
  73.      QApplication::instance()->sendEvent(this,new FunctionEvent(func));  
  74. }  
  75.   
  76. void QIoService::post(std::function<void()> func,int ms)  
  77. {  
  78.     auto lam = [&]()  
  79.     {  
  80.         QThread::currentThread()->wait(ms);  
  81.         post(func);  
  82.     };  
  83.     QtConcurrent::run(lam);  
  84. }  
  85.   
  86. void QIoService::send(std::function<void()> func,int ms)  
  87. {  
  88.     auto lam = [&]()  
  89.     {  
  90.         QThread::currentThread()->wait(ms);  
  91.         send(func);  
  92.     };  
  93.     QtConcurrent::run(lam);    
  94. }  
  95.   
  96. bool QIoService::event ( QEvent * e)  
  97. {  
  98.     if(e->type()==FunctionEvent::myType)  
  99.     {  
  100.         FunctionEvent *fe=(FunctionEvent *)e;  
  101.         fe->func();  
  102.         return true;  
  103.         //这个他会自动删除,不用我们自己手工delete  
  104.     }  
  105.     return false;  
  106. }  

注解:

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //比如你在另外一个线程,你收到数据,想修改界面。就弄个全局变量  
  2. QIoService g_ui_ios(false);  
[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //你只要  
  2. g_ui_ios.send([你的变量]  
  3. {  
  4.    //修改界面数据,这个会在主线程执行  
  5. });  
  6.   
  7. //如果你是想写个任务队列,  
  8. QIoService g_worker_ios(true);  
[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //你要把某段事情丢到其他线程执行,就  
  2. g_worker_ios.send([]  
  3. {  
  4.   //这段会在其他线程执行。  
  5.   如果执行完了,又想在主线程执行某段,这里可以继续  
  6.   //g_ui_ios.send([]  
  7.   {  
  8.     //这段会在主线程执行  
  9.   });  
  10. });  



三、更新

2016年8月27日 第一次更新

http://blog.csdn.net/qq2399431200/article/details/52335517

原文地址:https://www.cnblogs.com/findumars/p/6568635.html