最近看到在项目解决方案中有两种实现方式,sdk方式和mfc实现,sdk中消息及窗口过程的处理在mfc仅用重载PreTranslateMessage这个函数就可以实现,总结说明一下这个函数。
1.PreTranslateMessage的实现及功能
MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但实际的消息循环代码位于CWinThread中,CWinApp只是从CWinThread中继承而来,简化后的代码如下:
BOOL CWinThread::PumpMessage()
{
_AFX_THREAD_STATE *pState = AfxGetThreadState();
::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
if (!AfxPreTranslateMessage(&(pState->m_msgCur)))
{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}
AfxPreTranslateMessage中会调用WalkPreTranslateTree,WalkPreTranslateTree的实现如下:
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
ASSERT(pMsg != NULL);
// walk from the target window up to the hWndStop window checking
// if any window wants to translate this message
for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
{
// target window is a C++ window
if (pWnd->PreTranslateMessage(pMsg))
return TRUE; // trapped by target window (eg: accelerators)
}
// got to hWndStop window without interest
if (hWnd == hWndStop)
break;
}
return FALSE; // no special processing
}
因此,重载PreTranslateMessage可以过滤窗口消息派发给窗口函数TrnaslateMessage和DispatchMessae()的消息,处理键盘和鼠标消息。而这个过程在sdk中要窗口过程函数来实现。
2.说明
有上段代码可以看到,PreTranslateMessage返回TRUE时,TrnaslateMessage和DispatchMessae不会被调用来翻译和分发消息给相应的窗口;若返回值为 FALSE,才会调用翻译和分发消息函数。
PreTranslateMessage是CWnd类的虚拟函数,通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。
PreTranslateMessage是CWnd类的虚拟函数,通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。
可以按自己的需要来重载这个函数:
BOOL CCEJvmApp::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
switch (pMsg->message)
{
case WM_KEYDOWN: //按键按下
......
break;
case WM_KEYUP: //按键抬起
......
break;
case WM_LBUTTONUP: //鼠标左键松开
......
break;
case WM_LBUTTONDOWN: //鼠标左键按下
......
break;
default:
break;
}
return CWinApp::PreTranslateMessage(pMsg);
}