您的位置:首页 > 编程语言 > Qt开发

qt 消息处理机制深入分析(基于window平台)

2017-05-17 19:48 453 查看
在说明qt消息机制前,有必要说明下window下的消息处理机制。一 windows消息处理机制:1  注册窗口类(指定窗口函数),可以注册多个窗口类2  进入消息循环形式如下:首先取消息PeekMessage(&msg,0,0,0,PM_REMOVE); 从应用程序队列,也就是从主线程的消息队列中。接着转换消息并派发:TranslateMessage(&msg);DispatchMessage(&msg);  3  窗口函数就负责处理相应的消息。二 qt中的消息处理机制:      1 首先我们要关注的CApplication类,该类在初始化的时候会通过QWindowsClipboard::registerViewer()注册一个名字为“Qt5ClipboardView”窗口类,其中窗口函数为:qClipboardViewerWndProc,同时该类初始的调度器为QWindowsGuiEventDispatcher,该调度器也注册了一个窗口类,类名为"QEventDispatcherWin32_Internal_Widget1806862873",该类的窗口函数为:qt_internal_proc(这个是qt自定义事件的主要处理函数)      2 如果我们开发的是wiget风格应用,还会初始化一个MainWindow类,该类也会注册一个窗口函数,类名为"Qt5QWindowIcon",窗口函数为qWindowsWndProc(这个函数处理的是用户操作引起的系统事件,比如鼠标事件,键盘事件,点击事件。。。,这些事件可能又会触发Qt定义的事件,此时这类事件会被qt_internal_proc函数处理)      3 前面两步是注册了窗口函数,接着我们要看qt是如何进行消息派发的,在1中已经说到调度器为QWindowsGuiEventDispatcher,该类会调用:processEvents成员函数,调用父类的QEventDispatcherWin32::processEvents函数,在该函数中做了如下事情:a取消息来源有三个:
1)msg = d->queuedUserInputEvents.takeFirst();
2)msg = d->queuedSocketEvents.takeFirst();
3)haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
这三类消息代表不同的来源,其中第三个是系统推送来的消息(包括系统消息和用户自定义消息)
b 如果没有消息的话,判断关注的句柄是否有触发的消息,句柄通过QEventDispatcherWin32::registerEventNotifier注册
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
c 通过ab两种监测消息的机制,若有消息就直接:
if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) 这函数是过滤
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
至此qt的消息循环机制就已经完成。
4 回调函数,之前已经说过,由于注册了三个窗口类所以对应的应该有三个窗口函数,在此我分析其中两个关键的:
1)LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp):该函数是只处理自定义消息的, 套接字读写消息
WM_QT_SOCKETNOTIFIER,WM_QT_ACTIVATENOTIFIERS(对应套接字激活和失活状态),WM_QT_SENDPOSTEDEVENTS(异步消息),这三类消息都是qt自定义的,对于第一个消息,主要处理的是套接字读写事件,将套接字事件转化为QEvent事件然后通过QCoreApplication::sendEvent(sn->obj, &event)立即处理;第二类消息是指套接字注册成功或关闭时响应的消息,主要功能就是向函数WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event)重新注册关注的事件;第三个消息是最应用最广的消息,比如当我们调用异步函数发送消息时会触发该类消息QCoreApplication::postEvent(),该消息被触发后会从当前线程的自定义队列中取消息执行;
2)extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam):该函数处理用户操作产生的消息,比如鼠标等,它做了以下事情:
1)const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);将windows消息转为qt事件
2)const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);在qt事件分类中处理该类消息。有的消息就直接处理,有的消息会postWindowSystemEvent(ev)到消息队列中windowSystemEventQueue;同时发出WM_QT_SENDPOSTEDEVENTS消息以经过window消息循环回调第1)个函数处理,达到异步效果。
至此qt消息循环应该已经算基本清楚了。下次将会讨论qt内部消息是怎么传递的。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: