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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM