在 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 系統還提供了一個 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。
先決條件:有編譯成功的多線程庫 如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