qt 消息处理机制与window消息处理机制的比较
一:windows程序的消息處理?
windows程序的處理大概一致
如下:
1.0 windows 消息處理機制:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
? ? ? ? PSTR szCmdLine, int iCmdShow)
{
? ? static TCHAR szAppName[] = TEXT("Hello");
? ? HWND ? hwnd;
? ? MSG ? ?msg;
? ? WNDCLASS wndclass;
? ? //fill wndclass
? ? wndclass.lpfnWndProc ?= WndProc;
? ? ...
? ? RegisterClass(&wndclass);
? ? hwnd = CreateWindow( .... ); ? ? ?// creation parameters
? ? ShowWindow(hwnd, iCmdShow);
? ? UpdateWindow(hwnd);
? ? while(GetMessage(&msg, NULL, 0, 0)) ?{ //這一塊位置得到消息
? ? ? ? TranslateMessage(&msg);//轉換消息
? ? ? ? DispatchMessage(&msg);//分發消息到系統處理
? ? }
? ? return msg.wParam;
}
1.1 這是分發消息的回調函數熟悉windows程序應該不難看懂
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)?
{
? ? HDC hdc;
? ? PAINTSTRUCT ps;
? ? RECT rect;
? ? switch(message) {
? ? ? ? case WM_CREATE:
? ? ? ? ? ? return 0;
? ? ? ? case WM_PAINT://重繪、比如窗口大小拉伸
? ? ? ? ? ? ...
? ? ? ? ? ? return 0;
? ? ? ? case WM_DESTROY:
? ? ? ? ? ? PostQuitMessage(0);
? ? ? ? ? ? return 0;
? ? }
? ? return DefWindowProc(hwnd, message, wParam, lParam); // windows 操作系統內部的消息機制、系統調用函數;
}
二 Qt消息處理機制
2.0 Qt的消息機制
QEventDispatcherWin32:
注冊窗口類別,并創建一個隱藏窗口 (QEventDispatcherWin32_Internal_WidgetXXXX)
窗口的回調函數 qt_internal_proc()
安裝WH_GETMESSAGE類型的鉤子函數 qt_GetMessageHook()
bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)?
if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) ?與上面的消息循環:的while一樣 、得到過濾所有消息
{
?? ?TranslateMessage(&msg);//轉換消息
?? ?DispatchMessage(&msg); //分發消息
}
DispatchMessage(&msg); //分發消息
分發消息的或回調函數、這個與windows程序的CALLBACK WndProc一樣
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
2.1 下面就是從系統獲得的消息后Qt封裝消息后所作的事情
這個就是Qt的消息回調:
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
? ? if (message == WM_NCCREATE)
? ? ? ? return true;
?? ?// MSG windows 消息結構:
? ? MSG msg;
? ? msg.hwnd = hwnd;
? ? msg.message = message;
? ? msg.wParam = wp;
? ? msg.lParam = lp;
? ? QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
? ? long result;
? ? if (!dispatcher) {
? ? ? ? if (message == WM_TIMER)
? ? ? ? ? ? KillTimer(hwnd, wp);
? ? ? ? return 0;
? ? } else if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result)) {
? ? ? ? return result;
? ? }
?
#ifdef GWLP_USERDATA
? ? QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
#else
? ? QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);
#endif
? ? QEventDispatcherWin32Private *d = 0;
? ? if (q != 0)
? ? ? ? d = q->d_func();
?? ?// 下面 WM_QT_SOCKETNOTIFIER socket Qt 事件底層的處理機制、處理網絡的消息事件
? ? if (message == WM_QT_SOCKETNOTIFIER) {
? ? ? ? // socket notifier message
? ? ? ? int type = -1;
? ? ? ? switch (WSAGETSELECTEVENT(lp)) { //在非阻塞模式下利用socket事件的消息機制,Server端與Client端之間的通信處于異步狀態下
? ? ? ? case FD_READ: //socket 文件描述符 read 、有數據到達時發生
? ? ? ? case FD_ACCEPT: //socket 文件描述符 接收連接 、 作為客戶端連接成功時發生
? ? ? ? ? ? type = 0;
? ? ? ? ? ? break;
? ? ? ? case FD_WRITE: //socket 文件描述符寫 、有數據發送時產生
? ? ? ? case FD_CONNECT: ?//socket 文件描述符發起連接 、 作為服務端等待連接成功時發生?? ?
? ? ? ? ? ? type = 1;
? ? ? ? ? ? break;
? ? ? ? case FD_OOB: //socket 文件描述符收到數據 、 收到外帶數據時發生
? ? ? ? ? ? type = 2;
? ? ? ? ? ? break;
? ? ? ? case FD_CLOSE: //socket 文件描述符關閉斷開連接 、套接口關閉時發生
? ? ? ? ? ? type = 3;
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? if (type >= 0) {
? ? ? ? ? ? Q_ASSERT(d != 0);
? ? ? ? ? ? QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
? ? ? ? ? ? QSNDict *dict = sn_vec[type];
?
? ? ? ? ? ? QSockNot *sn = dict ? dict->value(wp) : 0;
? ? ? ? ? ? if (sn == nullptr) {
? ? ? ? ? ? ? ? d->postActivateSocketNotifiers();
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? Q_ASSERT(d->active_fd.contains(sn->fd));
? ? ? ? ? ? ? ? QSockFd &sd = d->active_fd[sn->fd];
? ? ? ? ? ? ? ? if (sd.selected) {
? ? ? ? ? ? ? ? ? ? Q_ASSERT(sd.mask == 0);
? ? ? ? ? ? ? ? ? ? d->doWsaAsyncSelect(sn->fd, 0);
? ? ? ? ? ? ? ? ? ? sd.selected = false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? d->postActivateSocketNotifiers();
?
? ? ? ? ? ? ? ? // Ignore the message if a notification with the same type was
? ? ? ? ? ? ? ? // received previously. Suppressed message is definitely spurious.
? ? ? ? ? ? ? ? const long eventCode = WSAGETSELECTEVENT(lp);
? ? ? ? ? ? ? ? if ((sd.mask & eventCode) != eventCode) {
? ? ? ? ? ? ? ? ? ? sd.mask |= eventCode;
? ? ? ? ? ? ? ? ? ? QEvent event(type < 3 ? QEvent::SockAct : QEvent::SockClose);
? ? ? ? ? ? ? ? ? ? QCoreApplication::sendEvent(sn->obj, &event);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return 0;
? ? } else if (message == WM_QT_ACTIVATENOTIFIERS) { // 處理postEvent事件
? ? ? ? Q_ASSERT(d != 0);
?? ??? ?// postEvent() 事件,因為是隊列的存儲的方式,郵遞發送消息、直接返回
?? ??? ?
? ? ? ? // Postpone activation if we have unhandled socket notifier messages
? ? ? ? // in the queue. WM_QT_ACTIVATENOTIFIERS will be posted again as a result of
? ? ? ? // event processing.
? ? ? ? MSG msg;//異步調用
? ? ? ? if (!PeekMessage(&msg, d->internalHwnd,
? ? ? ? ? ? ? ? ? ? ? ? ?WM_QT_SOCKETNOTIFIER, WM_QT_SOCKETNOTIFIER, PM_NOREMOVE)
? ? ? ? ? ? && d->queuedSocketEvents.isEmpty()) { // d->queuedSocketEvents 消息隊列如果消息有很多的時候都會加入這個隊列、這個就是關于Qt::connect();參數:地址
? ? ? ? ? ? // register all socket notifiers
? ? ? ? ? ? for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
? ? ? ? ? ? ? ? ?it != end; ++it) {
? ? ? ? ? ? ? ? QSockFd &sd = it.value();
? ? ? ? ? ? ? ? if (!sd.selected) {
? ? ? ? ? ? ? ? ? ? d->doWsaAsyncSelect(it.key(), sd.event);
? ? ? ? ? ? ? ? ? ? // allow any event to be accepted
? ? ? ? ? ? ? ? ? ? sd.mask = 0;
? ? ? ? ? ? ? ? ? ? sd.selected = true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? d->activateNotifiersPosted = false;
? ? ? ? return 0;
? ? } else if (message == WM_QT_SENDPOSTEDEVENTS ?// 處理 Qt sendPostEvent()發送事件
? ? ? ? ? ? ? ?// we also use a Windows timer to send posted events when the message queue is full
?? ??? ??? ? ? // WM_QT_SENDPOSTEDEVENTS : 這個消息是我們Qt程序大部分走的事件,特殊情況除外。
? ? ? ? ? ? ? ?|| (message == WM_TIMER
? ? ? ? ? ? ? ? ? ?&& d->sendPostedEventsWindowsTimerId != 0
? ? ? ? ? ? ? ? ? ?&& wp == (uint)d->sendPostedEventsWindowsTimerId)) {
? ? ? ? const int localSerialNumber = d->serialNumber.load();
? ? ? ? if (localSerialNumber != d->lastSerialNumber) {
? ? ? ? ? ? d->lastSerialNumber = localSerialNumber;
? ? ? ? ? ? q->sendPostedEvents();//因為sendevent是同步所以直接進入進行調用
? ? ? ? }
? ? ? ? return 0;
? ? } else if (message == WM_TIMER) {//系統定時器超時
? ? ? ? Q_ASSERT(d != 0);
? ? ? ? d->sendTimerEvent(wp);
? ? ? ? return 0;
? ? }
?
? ? return DefWindowProc(hwnd, message, wp, lp); // 這個與windows程序一樣的地方。
}
另外還有一點很重要的:大家都知道Qt消息處理比windows處理的塊,Qt程序通過一通處理才調用DefWindowProc傳給系統所以Qt系統的消息機制是比windows的消息慢的原因之一;
不過他也有它優點:qt的信號與槽函數讓我們讓我們編程更方便。
2.3 消息全局通知事件
另外我們都知道我們開發的系統、所有的消息都會到這個類QApplication::notify事件過濾所有的事件:
其實QApplication繼承QGuiApplication類;
bool QGuiApplication::notify(QObject *object, QEvent *event)
{
? ? if (object->isWindowType())
? ? ? ? QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event);
? ? return QCoreApplication::notify(object, event);
}
2.4 消息的組裝
下面是所有的消息類型處理:在我們開發的系統中別人使用processEvent發送消息是比較高效的。
原因:這個消息直達經過的處理的少。
void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
? ? switch(e->type) {
? ? case QWindowSystemInterfacePrivate::FrameStrutMouse:
? ? case QWindowSystemInterfacePrivate::Mouse:
? ? ? ? QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Wheel:
? ? ? ? QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Key:
? ? ? ? QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Touch:
? ? ? ? QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::GeometryChange:
? ? ? ? QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Enter:
? ? ? ? QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Leave:
? ? ? ? QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ActivatedWindow:
? ? ? ? QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::WindowStateChanged:
? ? ? ? QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::WindowScreenChanged:
? ? ? ? QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
? ? ? ? QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
? ? ? ? QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::FlushEvents: {
? ? ? ? QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
? ? ? ? QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Close:
? ? ? ? QGuiApplicationPrivate::processCloseEvent(
? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ScreenOrientation:
? ? ? ? QGuiApplicationPrivate::reportScreenOrientationChange(
? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ScreenGeometry:
? ? ? ? QGuiApplicationPrivate::reportGeometryChange(
? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
? ? ? ? QGuiApplicationPrivate::reportLogicalDotsPerInchChange(
? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ScreenRefreshRate:
? ? ? ? QGuiApplicationPrivate::reportRefreshRateChange(
? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::ThemeChange:
? ? ? ? QGuiApplicationPrivate::processThemeChanged(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Expose:
? ? ? ? QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::Tablet:
? ? ? ? QGuiApplicationPrivate::processTabletEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::TabletEnterProximity:
? ? ? ? QGuiApplicationPrivate::processTabletEnterProximityEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::TabletLeaveProximity:
? ? ? ? QGuiApplicationPrivate::processTabletLeaveProximityEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
? ? ? ? break;
#ifndef QT_NO_GESTURES
? ? case QWindowSystemInterfacePrivate::Gesture:
? ? ? ? QGuiApplicationPrivate::processGestureEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
? ? ? ? break;
#endif
? ? case QWindowSystemInterfacePrivate::PlatformPanel:
? ? ? ? QGuiApplicationPrivate::processPlatformPanelEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
? ? ? ? break;
? ? case QWindowSystemInterfacePrivate::FileOpen:
? ? ? ? QGuiApplicationPrivate::processFileOpenEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
? ? ? ? break;
#ifndef QT_NO_CONTEXTMENU
? ? ? ? case QWindowSystemInterfacePrivate::ContextMenu:
? ? ? ? QGuiApplicationPrivate::processContextMenuEvent(
? ? ? ? ? ? ? ? ? ? static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
? ? ? ? break;
#endif
? ? case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
? ? ? ? QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
? ? ? ? break;
? ? default:
? ? ? ? qWarning() << "Unknown user input event type:" << e->type;
? ? ? ? break;
? ? }
}
2.5 常用的消息過濾事件
通過2.4組裝的消息最終到達、此處。經過這些之后:之前的windows消息現在都已映射為QT類型的消息、進入Qt消息處理機制中來、才有了我們的消息過濾等等消息事件鍵盤鼠標等等;
virtual void mouseDoubleClickEvent(QMouseEvent *event)
virtual void mouseMoveEvent(QMouseEvent *event)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
virtual void moveEvent(QMoveEvent *event)
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result)
virtual void paintEvent(QPaintEvent *event)
virtual void resizeEvent(QResizeEvent *event)
virtual void showEvent(QShowEvent *event)
virtual void tabletEvent(QTabletEvent *event)
virtual void wheelEvent(QWheelEvent *event)
重新實現上面的消息事件做我們的功能;
總結:
通過windows消息的運行機制與Qt的消息機制進行了對比。其實Qt在windows平臺上的消息傳遞依賴的是windows消息機制。只不過在開始時進行注冊消息攔截等一些封裝處理、加工成Qt消息在Qt程序中進行傳遞。
?
總結
以上是生活随笔為你收集整理的qt 消息处理机制与window消息处理机制的比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《趋势的力量》-- 观念决定了个人发展的
- 下一篇: H264 CAVLC 研究