引言
- 在VC編程中瘫证,需要往一個(gè)窗口發(fā)送消息時(shí),常常用到SendMessage和PostMessage毙籽。其中SendMessage是阻塞式的毡庆,發(fā)送消息后烙如,立即響應(yīng)消息毅否,響應(yīng)完成后才繼續(xù)往下執(zhí)行。而PostMessage是非阻塞式的螟加,發(fā)送的消息會放到消息隊(duì)列后,立即返回繼續(xù)往下執(zhí)行然爆。SendMessage和PostMessage都無需保證線程一致性徐许。即,可以無論在工作線程中還是主線程中雌隅,都能向指定的窗口發(fā)送消息。
- 在Qt編程中修械,很自然的會想到sendEvent和postEvent來實(shí)現(xiàn)VC這種消息發(fā)送機(jī)制检盼。sendEvent是阻塞式的,發(fā)送事件后吨枉,立即對事件做出響應(yīng)。而postEvent則是非阻塞式的柬唯,發(fā)送的事件會放到事件隊(duì)列后圃庭,立即返回繼續(xù)往下執(zhí)行。需要注意的是拘央,sendEvent必須滿足線程一致性书在,即必須保證事件接收對象所駐留的線程與sendEvent的調(diào)用線程保持一致。而postEvent無需保證這一點(diǎn)儒旬。
- 因此遏乔,可以直接使用postEvent實(shí)現(xiàn)PostMessage機(jī)制发笔。而在事件接收對象所駐留的線程與sendEvent的調(diào)用線程是同一個(gè)線程時(shí),可以使用sendEvent來實(shí)現(xiàn)SendMessage機(jī)制捻激。但是當(dāng)sendEvent的調(diào)用線程與事件接收對象所駐留的線程不一致時(shí)前计,這里需要借助postEvent和QEventLoop共同完成。
- QEventLoop類為我們提供了一種進(jìn)入和退出一個(gè)事件循環(huán)的方法男杈。在任何時(shí)候伶棒,你都可以創(chuàng)建一個(gè)QEventLoop實(shí)例,然后調(diào)用exec()來啟動(dòng)一個(gè)事件循環(huán)實(shí)現(xiàn)阻塞效果肤无。在這個(gè)循環(huán)期間,可以調(diào)用exit()來強(qiáng)制使exct()返回竞漾。
實(shí)現(xiàn)方案
#pragma once
#include <QObject>
#include <QEvent>
#include <QVariant>
void QPostMessage(QObject* obj, int msg, QVariant params);
long QSendMessage(QObject* obj, int msg, QVariant params);
static long s_rst = 0;
class LEvent : public QObject, public QEvent
{
public:
LEvent(int msg, const QVariant params = QVariant(), long& rst = s_rst);
~LEvent();
public:
static Type m_eventType;
int m_message = 0;
const QVariant& m_params;
long& m_rst;
};
#include "LEvent.h"
QEvent::Type LEvent::m_eventType = (QEvent::Type)QEvent::registerEventType();
LEvent::LEvent(int msg, const QVariant params/* = QVariant()*/, long& rst/* = s_rst*/)
: QEvent(m_eventType), m_message(msg), m_params(params), m_rst(rst)
{
}
LEvent::~LEvent()
{
}
void QPostMessage(QObject* obj, int msg, QVariant params)
{
QCoreApplication::postEvent(obj, new LEvent(msg, params));
}
long QSendMessage(QObject* obj, int msg, QVariant params)
{
long lResult = 0;
if (obj->thread() == QThread::currentThread())
{
//事件隊(duì)列不會刪除事件业岁。通常的方法是在棧上創(chuàng)建事件
LEvent e(msg, params, lResult);
QCoreApplication::sendEvent(obj, &e);
}
else
{
//事件隊(duì)列將獲得事件的所有權(quán)并在事件發(fā)送后刪除它寇蚊。必須在堆上創(chuàng)建事件
LEvent* e = new LEvent(msg, params, lResult);
QCoreApplication::postEvent(obj, e, Qt::HighEventPriority);
QEventLoop loop;
// 當(dāng)事件處理完畢后,事件實(shí)例會被銷毀幔荒,通知loop退出事件循環(huán)
QObject::connect(e, SIGNAL(destroyed(QObject*)), &loop, SLOT(quit()));
loop.exec(QEventLoop::ExcludeUserInputEvents);
}
return lResult;
}
參考文章:
https://note.youdao.com/ynoteshare1/index.html?id=79b2bd18897960d901608f1d219e56f0&type=note