原文地址:http://blog.csdn.net/wzyzb/archive/2009/03/05/3959564.aspx
PreTranslateMessage是消息在送給TranslateMessage函數(shù)之前被調(diào)用的,絕大多數(shù)本窗口的消息都要通過(guò)這里,比較常用,當(dāng)需要在MFC之前處理某些消息時(shí),常常要在這里添加代碼.
MFC 消息控制流最具特色的地方是CWnd類的虛擬函數(shù)PreTranslateMessage(),通過(guò)重載這個(gè)函數(shù),可以改變MFC的消息控制流程,甚至可以作一個(gè)全新的控制流出來(lái)。只有穿過(guò)消息隊(duì)列的消息才受PreTranslateMessage()影響,采用SendMessage()或其他類似的方式向窗口直接發(fā)送的而不經(jīng)過(guò)消息隊(duì)列的消息根本不會(huì)理睬PreTranslateMessage()的存在。
是否調(diào)用TranslateMessage()和DispatchMessage()是由一個(gè)名稱為PreTranslateMessage()函數(shù)的返回值決定的,如果該函數(shù)返回TRUE,則不會(huì)把該消息分發(fā)給窗口函數(shù)處理。
傳給PreTranslateMessage()的消息是未經(jīng)翻譯過(guò)的消息,它沒(méi)有經(jīng)過(guò)TranslateMessage()處理。可以在該函數(shù)中使用(pMsg->wParam==VK_RETURN)來(lái)攔截回車鍵。wParam中存放的是鍵盤上字符的虛擬碼。
PeekMessage和GetMessage的區(qū)別:
GetMessage在沒(méi)有消息的時(shí)候等待消息,cpu當(dāng)然低
PeekMessage沒(méi)有消息的時(shí)候立刻返回,所以cpu占用率高。
因?yàn)橛螒虿荒芸縲indows消息驅(qū)動(dòng),所以要用PeekMessage();
PretranslateMessage 的實(shí)現(xiàn),不得不談到MFC消息循環(huán)的實(shí)現(xiàn)。MFC通過(guò)CWinApp類中的Pumpmessage函數(shù)實(shí)現(xiàn)消息循環(huán),但是實(shí)際的消息循環(huán)代碼位于 CWinThread中,CWinApp只是從CWinThread繼承過(guò)來(lái)。其簡(jiǎn)化后的代碼大概如下:
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;
}
可以看到,PumpMessage在實(shí)際的TranslateMessage和DispatchMessage發(fā)生之前會(huì)調(diào)用 AfxPreTranslateMessage,AfxPreTranslateMessage又會(huì)調(diào)用 CWnd::WalkPreTranslateTree(雖然也會(huì)調(diào)用其他函數(shù),但是這個(gè)最為關(guān)鍵),其代碼如下:
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
}
可以看到,代碼還是很直接的。從接受到消息的窗口層層往上遍歷,并調(diào)用PretranslateMessage看是否返回TRUE,是則結(jié)束,否則繼續(xù)。
這里有一個(gè)地方非常關(guān)鍵:CWnd *pWnd = CWnd::FromHandlePermanent(hWnd) 這一句代碼從當(dāng)前AfxModuleThreadState拿到Permanent句柄表,從而找到hWnd對(duì)應(yīng)的CWnd
MFC 中PreTranslateMessage是GetMessage(...)函數(shù)的下一級(jí)操作,即GetMessage(...)從消息隊(duì)列中獲取消息后,交由PreTranslateMessage()處理,若其返回FALSE則再交給TranslateMessage和 DispatchMessage處理(進(jìn)入WindowProc);
如果用SendMessage, 則消息直接交到WindowProc處理,所以GetMessage不會(huì)取得SendMessage的消息,當(dāng)然PreTranslateMessage也就不會(huì)被調(diào)用。 [Page]
如果用PostMessage,則消息進(jìn)入消息隊(duì)列,由GetMessage取得,PreTranslateMessage就有機(jī)會(huì)進(jìn)行處理。
例子:
按Enter,ESC按是不會(huì)退出了
BOOL CComboBoxExDlg::PreTranslateMessage(MSG* pMsg)
{
if(WM_KEYDOWN == pMsg->message )
{
UINT nKey = (int) pMsg->wParam;
if( VK_RETURN == nKey || VK_ESCAPE == nKey )
return TRUE ;
}
return CDialog::PreTranslateMessage(pMsg);
}
編輯框,如何響應(yīng)的這個(gè)回車的信息
如果你的編輯框定義如下
CEdidt m_cName; //ID號(hào)為IDC_E_NAME
BOOL CSecondDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call class
if (pMsg->message==WM_KEYDOWN)
{
//CWnd *p=GetDlgItem(IDC_E_NAME);
CWnd * hWnd=GetFocus();
//if(pMsg->wParam==13 && pMsg->hwnd==m_cName)
if(pMsg->wParam==13 && hWnd==&m_cName)
{
處理函數(shù)
return TRUE;
}
else
{
處理函數(shù)
}
}
return CDialog::PreTranslateMessage(pMsg);
}
posted on 2010-01-18 09:22
漂漂 閱讀(2959)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
深入vc++