QT---線程間通信


在 Qt 系統中,運行着一個GUI 主事件線程,這個主線程從窗口系統中獲取事件,並將它們分發到各個組件去處理。在 QThread 類中有一種從非主事件線程中將事件提交給一個對象的方法,也就是 QThread::postEvent()方法,該方法提供了Qt 中的一種 Thread-safe 的事件提交過程。提交的事件被放進一個隊列中,然后 GUI 主事件線程被喚醒並將此事件發給相應的對象,這個過程與一般的窗口系統事件處理過程是一樣的。當事件處理過程被調用時,是在主事件線程中被調用的,而不是在調用QThread::postEvent 方法的線程中被調用。

 

 

1.、系統定義的事件的提交
在 Qt 系統中,定義了很多種類的事件,如定時器事件、鼠標移動事件、鍵盤事件、窗口控件事件等。通常,事件都來自底層的窗口系統。Qt 的主事件循環函數從系統的事件隊列中獲取這些事件,並將它們轉換為 QEvent,然后傳給相應的 QObjects 對象。
如下所示:
QWidget *mywidget;
void MyThread::run()
 {
   QThread::postEvent(MyWidget, new QPaintEvent(QRect(0,0,100,100)));
 }
在MyThread線程中發送重畫事件給MyWidget窗體類。
MyWidget的paintEvent事件響應會被自動調用,用以響應MyThread發送過來的重畫事件。
void MyWidget::paintEvent(QPaintEvent*)
{
}

  
2.、自定義事件的提交
  為了滿足用戶的需求,Qt 系統還提供了一個 QCustomEvent 類,用於用戶自定義事件,這些自定義事件可以利用 QThread::postEvent() 或者QApplication::postEvent() 被發給各種控件或其他 QObject 實例,而 QWidget 類的子類可以通過 QWidget::customEvent() 事件處理函數方便地接收到這些自定義的事件。需要注意的是:QCustomEvent 對象在創建時都帶有一個類型標識 id 以定義事件類型,為了避免與 Qt 系統定義的事件類型沖突,該 id 值應該大於枚舉類型 QEvent::Type 中給出的 "User" 值。
  如下所示:
  UserEvent類是用戶自定義的事件類,其事件標識為346798,顯然不會與系統定義的事件類型沖突。
  class UserEvent : public QCustomEvent  //用戶自定義的事件類
  {
  public:
  UserEvent(QString s) : QCustomEvent(346798), sz(s) { ; }
  QString str() const { return sz; }
  private:
  QString sz;  
  };
  
  UserThread類是由QThread類繼承而來的子類,在該類中除了定義有關的變量和線程控制函數外,最主要的是定義線程的啟動函數UserThread::run(),在該函數中創建了一個用戶自定義事件UserEvent,並利用QThread類的postEvent函數提交該事件給相應的接收對象。
  class UserThread : public QThread   //用戶定義的線程類
  {
  public:
  UserThread(QObject *r, QMutex *m, QWaitCondition *c);
  QObject *receiver;
  }
  void UserThread::run()   //線程類啟動函數,在該函數中創建了一個用戶自定義事件
  {UserEvent *re = new UserEvent(resultstring);
   QThread::postEvent(receiver, re);
  }
  UserWidget類是用戶定義的用於接收自定義事件的QWidget類的子類,該類利用slotGo()函數創建了一個新的線程recv(UserThread類),當收到相應的自定義事件(即id為346798)時,利用customEvent函數對事件進行處理。
  void UserWidget::slotGo()  //用戶定義控件的成員函數
  {mutex.lock(); 
  if (! recv)
  recv = new UserThread(this, &mutex, &condition);
  recv->start();
  mutex.unlock();
  }
  void UserWidget::customEvent(QCustomEvent *e)  //用戶自定義事件處理函數
  {if (e->type()==346798) 
  {
  UserEvent *re = (UserEvent *) e;
      newstring = re->str();
    }
  }
  在這個例子中,UserWidget對象中創建了新的線程UserThread,用戶可以利用這個線程實現一些周期性的處理(如接收底層發來的消息等),一旦滿足特定條件就提交一個用戶自定義的事件,當UserWidget對象收到該事件時,可以按需求做出相應的處理,而一般情況下,UserWidget對象可以正常地執行某些例行處理,而完全不受底層消息的影響。
   
  QT多線程程序的編譯
先決條件:有編譯成功的多線程庫 如libqt-mt.so(QT庫)或 libqte-mt.so(QTE庫)
   WINDOWS下:在qconfig.h 文件中增加一個選項來定義宏 QT_THREAD_SUPPORT
Linux下:在makefile中的鏈接選項中加入多線程庫-lqt-mt或-lqte-mt,在編譯選項中增加-DQT_THREAD_SUPPORT 來增加線程支持宏 QT_THREAD_SUPPORT。
 
http://blog.csdn.net/yiyaaixuexi/article/details/6036820


免責聲明!

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



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