近期在又一次學習Qt的時候,由於要涉及到子線程與主線程傳遞消息,所以便琢磨了一下。順便把有用的記錄下來,方便自己以后查詢及各位同仁的參考!
特此聲明,本篇博文主要講述有用的,也就是直接說明怎么實現,就不打算陳述一大堆理論啦,只是,還是建議大家去查查對應的理論比較好。這樣能對Qt的消息傳送機制的理解更加深入。
依據網上大多數人的資料,要實現自己定義消息,須要從QEvent 派生一個自己定義的事件;事實上也能夠不須要,僅僅要使用QEvent::Type自己定義一個事件即可了。
在這里,本人把兩種實現方法都在這里講述一下!
一、這里先講述使用 QEvent::Type 定義一個自己定義事件
1、新建一個新的project “myEvent” 。在 ui 界面加入一個button,並未button加入 onclick() 響應函數。
2、在 widget.h 頭文件使用 QEvent::Type 定義兩個自己定義事件。
3、又一次實現 event() 虛函數
bool event(QEvent* e);4、加入 #include<QEvent>
整個頭文件例如以下:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
bool event(QEvent* e);
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QEvent::Type myEvent1;
QEvent::Type myEvent2;
};
#endif // WIDGET_H
5、使用QEvent::registerEventType() 靜態函數為剛才兩個自己定義事件注冊值。
6、又一次實現 event() 函數 。
7、在 button響應函數里面發送時間消息。
widget.cpp 文件例如以下:
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QCoreApplication>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
myEvent1 = static_cast<QEvent::Type>(QEvent::registerEventType(-1));
myEvent2 = static_cast<QEvent::Type>(QEvent::registerEventType(-1));
}
Widget::~Widget()
{
delete ui;
}
bool Widget::event(QEvent* e)
{
if(e->type() == myEvent1){
QMessageBox::warning(this, tr("event"), tr("myEvent1"), QMessageBox::Yes); return true;
}else if(e->type() == myEvent2){
QMessageBox::warning(this, tr("event"), tr("myEvent2"), QMessageBox::Yes); return true;
}
return QWidget::event(e);
}
void Widget::on_pushButton_clicked()
{
QCoreApplication::sendEvent(this, &QEvent(myEvent1));
QCoreApplication::sendEvent(this, &QEvent(myEvent2));
}
編譯執行后界面例如以下:

二、從 QEvent 派生一個自己定義事件類,類名取為 myEvent 。
1、myevent.h 頭文件例如以下。里面自己定義了三個自己定義事件,分別為 m_event1, m_event2, m_event3:
#ifndef MYEVENT_H
#define MYEVENT_H
#include <QEvent>
class myEvent : public QEvent
{
public:
myEvent(Type e);
public:
static Type m_event1;
static Type m_event2;
static Type m_event3;
};
#endif // MYEVENT_H
2 、在myevent.cpp 文件里面使用QEvent::registerEventType() 為自己定義的事件注冊。
myevent.cpp 文件例如以下:
#include "myevent.h"
#include <QEvent>
QEvent::Type myEvent::m_event1 = static_cast<QEvent::Type>(QEvent::registerEventType());
QEvent::Type myEvent::m_event2 = static_cast<QEvent::Type>(QEvent::registerEventType());
QEvent::Type myEvent::m_event3 = static_cast<QEvent::Type>(QEvent::registerEventType());
myEvent::myEvent(Type e):QEvent(e)
{
}
3、在 widget.cpp 文件 加入 myevent.h 頭文件 。
4、改動 widget.cpp 文件中面的button響應函數例如以下:
void Widget::on_pushButton_clicked()
{
myEvent e(myEvent::m_event1);
QCoreApplication::sendEvent(this, &e);
}5、
改動 widget.cpp 文件中面的 event() 函數例如以下:
bool Widget::event(QEvent* e)
{
if(e->type() == myEvent1){
QMessageBox::warning(this, tr("event"), tr("myEvent1"), QMessageBox::Yes); <pre name="code" class="cpp"> return true;
}else if(e->type() == myEvent2){
QMessageBox::warning(this, tr("event"), tr("myEvent2"), QMessageBox::Yes);
<pre name="code" class="cpp"><pre name="code" class="cpp"> return true;
}else if(e->type() == myEvent::m_event1){ QMessageBox::warning(this, tr("myEvent"), tr("m_event1"), QMessageBox::Yes); return true; } else if(e->type() == myEvent::m_event2){ QMessageBox::warning(this, tr("myEvent"), tr("m_event2"), QMessageBox::Yes); return true; } return QWidget::event(e);}
然后又一次編譯執行,效果例如以下:

三 、 前面講的都是在主線程里面傳遞事件消息,接下來講述怎樣 在子線程里面 往主線程 傳遞事件消息。
1、從 QThread 派生一個自己定義事件類,類名取為 myThread , 並又一次實現 run() 虛函數。mythread.h 頭文件例如以下:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class myThread : public QThread
{
Q_OBJECT
public:
explicit myThread(QObject *parent = 0);
signals:
public slots:
protected:
void run();
};
#endif // MYTHREAD_H
2、在mythread.cpp 里面又一次實現 run() 函數。在里面實現向主線程發送事件消息,mythread.cpp 文件例如以下:
#include "mythread.h"
#include "myevent.h"
#include <QCoreApplication>
myThread::myThread(QObject *parent) :
QThread(parent)
{
}
void myThread::run()
{
myEvent e(myEvent::m_event2);
QCoreApplication::postEvent(this->parent(), new myEvent(myEvent::m_event2));
//this->exec();
}
3、在 widget.h 里面加入 mythread.h 頭文件, 然后定義一個子線程對象, 例如以下:
#include"mythread.h"
myThread*m_pThread;
4、在堆內存里面為m_pThread開辟一個內存空間,例如以下:
<span style="color:#000000;">Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
m_pThread = new myThread(this);
。。。。。。
}</span>
5、在 ui 界面 加入還有一個button。並為它加入 onclick() 事件響應。然后在里面執行子線程,例如以下:
void Widget::on_pushButton_2_clicked()
{
m_pThread->start();
}
編譯執行程序,效果例如以下:

四、QCoreApplication::postEvent(); 和 QCoreApplication::sendEvent(); 的差別。
在前面的程序中發送 事件消息 的時候用到了 QCoreApplication::postEvent(); 和 QCoreApplication::sendEvent(); 兩個函數,這里可不是隨便使用的,這兩個函數時又差別的!
1、QCoreApplication::sendEvent(); 依據Qt Asistant 里面的講述。這個函數直接將事件消息直接發送給接受者進行處理,等到事件處理完成后才返回;而且使用它所傳遞的消息事件是在 棧(stack) 上創建的,也就是說它的內存空間是有編譯器來自己主動管理的。
2、QCoreApplication::postEvent(); 依據Qt Asistant 里面的講述,使用這個函數來傳遞時間消息時。它將事件消息發送到接受者的的消息隊列里面,然后馬上返回。不須要等到事件處理完成才返回;而且使用它所傳遞的消息事件是在 堆(heep) 上創建的。也就是說它的內存空間是又程序猿自己管理的,如用 new 創建的變量。
這兩個函數對事件的處理方式就像使用 repaint() 和 paint() 這兩個函數對界面進行重畫一樣。前者直接對界面進行重畫操作;后者先將重畫事件放到消息隊列里面,等到適當的時候在對界面進行重畫操作。
在上面的子線程給主線程傳遞消息的時候使用的就是QCoreApplication::postEvent(); 函數。由於這里必須保證在子線程退出之前,若子線程所傳遞的事件消息還未被主線程處理的話,子線程所傳遞的消息仍然是可用的。
好了。主線程內事件的傳遞與子線程向主線程傳遞事件消息的方法就介紹到這里了。至於Qt 的事件傳送機制。這里就沒有怎么講了。只是還是建議讀者好好去了解一下的好。
