MFC VC PreTranslateMessage详解

来源:互联网 发布:文字办公软件 编辑:程序博客网 时间:2024/05/15 22:18

1.函数原型:(MSDN)

virtual BOOL PreTranslateMessage( MSG *pMsg );

功能:

    Override   this   function   to   filter   window   messages   before   they   are  dispatched   to   the   Windows   functions TranslateMessage   and DispatchMessage. The   default   implementation   performs   accelerator-key   translation,   so   you   must   call   the  CWinApp::PreTranslateMessage   member   function   in   your   overridden   version.  
  重载该函数可以实现窗口消息在派发给窗口函数TrnaslateMessage和DispatchMessae()之前的过滤.缺省的实现是完成加速键的翻译.因为您必须在你的重载版本中调用CWinApp:PreTranslateMessage()函数.

在MFC中,PreTranslateMessage是虚函数,我们可以重载它来处理键盘和鼠标消息。  
在sdk中,这又有所不同,我们必须在回调函数中LRESULT   CALLBACK   WndProc(HWND   hWnd,   UINT  message,   WPARAM   wParam,   LPARAM   lParam)处理消息:  
  它和PreTranslateMessage起的作用是类似的。只是MFC封装的更好而已

2.说明:

该函数表示在消息处理(TranslateMessge()和DispatchMessage()等)前所作的操作,如果函数返回值为TRUE,那么消息处理即终止,不会调用TranslateMessge()和DispatchMessage()来翻译和分发消息给相应的窗口;若返回值为 FALSE,才会调用翻译和分发消息函数。

该函数是MFC消息控制流最具特色的地方,它是CWnd类的虚拟函数,通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。

在win32程序中,关于消息有两种传递方式:

a.MFC消息,MFC会把所有的消息一条条放到一个AFX_MSGMAP_ENTRY结构中,形成一个数组,该数组存放了所有的消息和与它们相关的参数。也可以说是放到消息队列里去。

b. 采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息。

这两种方式中只有第一种(穿过消息队列的消息)才受PreTranslateMessage()影响,

第二种消息并不会理睬PreTranslateMessage()的存在。

 一、是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。

二、传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理。可以在该函数中使用(pMsg->wParam==VK_RETURN)来拦截回车键。

三、在WindowProc里不能处理WM_Char消息。(WindowProc函数见MFC消息响应机制一文)

四、SetWindowText会发送WM_Char给窗口。

五、PeekMessage和GetMessage的区别:

    GetMessage在没有消息的时候等待消息,cpu当然低

    PeekMessage没有消息的时候立刻返回,所以cpu占用率高。因为游戏不能靠windows消息驱动,所以要用PeekMessage();

另一篇文章中:


  在一个WIN32程序中,WINDOWS会将消息传递给相应的窗口。但是消息不是立即就被传递给相应的窗口,而是会从整个程序最顶层的窗口传递到下一级窗口,再传递到下一级窗口,直到传递给目标窗口。在整个过程中,有些消息,在某些特定的情况下,无法默认传递到目标窗口的。比如用户在EDIT控件中按下回车键,CANCEL键等,如果EDIT窗口之前有对话框窗口,对话框会默认处理回车消息(即响应ONOK函数,然后关闭对话框),然后退出消息传递。所以 EDIT会收不到。要解决这个问题,可以在EDIT窗口之前所有的对话框中重载PreTranslateMessage函数,然后在函数内加上:

if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN)     //如果消息类型为WM_KEYDOWN并且用户按下的是回车
  return FALSE;    //不翻译消息,直接将消息传递下去。具体可查MSDN。注意,这里返回值不能为TRUE,TRUE的意思是翻译消息后退出消息传递,如此一来虽然也能避开对话框默认处理,但是会退出消息传递,这样EDIT控件照样得不到消息。

如此,就可避开对话框默认处理,将消息传递下去。注意:只有对话框才会默认处理按下回车,CANCEL消息,其他控件窗口则不会,所以在其他窗口中不必重载PreTranslateMessage函数,当然如果重载了也不会错。

附:关于PreTranslateMessage()函数的小程序示例:

BOOL CSearchuserDlg::PreTranslateMessage(MSG* pMsg)
{

    if(pMsg->message==WM_KEYDOWN)  //判断是否有按键按下
    {
       switch(pMsg->wParam)
       {
          case VK_DOWN:     //表示是方向键中的向下的键

              //add handle code here

          break;

          case VK_UP:      //表示是方向键中的向上的键

               //add handle code here

          break;

          default:

          break;

       }

   }

}


BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
{
        // TODO: Add your specialized code here and/or call the base class
 
        //按键相应
        if (pMsg->message == WM_KEYDOWN)
        {
                if (pMsg->wParam == VK_DOWN)
                {
                        //向下键按下
                }
                else if (pMsg->wParam == VK_RIGHT)
                {
                        //向右键按下
                }
                else if (pMsg->wParam == VK_LEFT)
                {
                        //向左键按下
                }
                else if (pMsg->wParam == VK_UP)
                {
                        //向上键按下
                }
                else if(pMsg->wParam == VK_SHIFT)
                {
                        //VK_LSHIFT为左Shift键按下
                        //Shift键按下
                }
                else if(pMsg->wParam == VK_CONTROL)
                {
                        //Ctrl键按下
                }
                else if(pMsg->wParam>=VK_NUMPAD0 && pMsg->wParam<=VK_NUMPAD9)
                {
                        //小键盘数字键按下
                }
                else if(pMsg->wParam>=0x30 && pMsg->wParam<=0x39)
                {
                        //数字键按下(我记得不能使用VK_0)
                }
                else if(pMsg->wParam>=0x41 && pMsg->wParam<=0x5A)
                {
                        //键盘字母键按下(我记得不能使用VK_A)
                }
                else if(pMsg->wParam == VK_BACK)
                {
                        //退格键按下
                }
                else if(pMsg->wParam == VK_DELETE)
                {
                        //删除键按下
                }
                else if(pMsg->wParam == VK_F1)
                {
                        //F1键按下
                }
               
                //return true;  //使消息不再进行处理
        }
 
        if (pMsg->message == WM_KEYUP)
        {
                if(pMsg->wParam == VK_SHIFT)
                {
                        //Shift键弹起
                }
                else if(pMsg->wParam == VK_CONTROL)
                {
                        //Ctrl键弹起
                }
                //return true;  //使消息不再进行处理
        }
 
        return CDialog::PreTranslateMessage(pMsg);
}
同时按下CTRL:

BOOL   CDemo_DevStudioView::PreTranslateMessage(MSG*   pMsg)   //根据键盘上的按键对图形进行相应的操作  
  {  
   
  if(pMsg->message==256)   //   256有键按下,46   DEL键  
  {  
   
  switch(pMsg->wParam)    
  {  
  ///向左键被按下    
  case   37:  
  {  
  //同时按下了CTRL键  
  if(::GetKeyState(VK_CONTROL)       <       0)        
  {        
   
  }  
  }  
  }  
  }

原创粉丝点击