[VC- MFC] PreTranslateMessage() 函数

     这两天折腾一个程序,是MFC里一个菜单响应。在CView里我加载了一个空间CListCtrl,然后在右键点击List里的数据项时,弹出pop菜 单,然后响应菜单项上的函数处理,按照以前自己的经验直接在CView里添加菜单项的响应函数,结果在程序调试时,没有得到预期的效果,点击菜单项没反 应,跟踪后发现消息没有走到处理过程里,觉得很奇怪。点击菜单项后产生的WM_COMMAND消息应该被发送到CView里的处理函数了,为啥实际过程中 不对?有蹊跷。

   上Google上搜,看了几个帖子,没收获。我仔细回顾了一下MFC里的消息处理机制,是不是菜单项的消息没有被CView截获?带着疑问我做了个测试, 果然,我在List里弹出的菜单所发送的消息是被List控件截获处理了,看来自己对消息处理机制了解的不够深刻啦!
    下面做的事就是在CListCtrl里添加消息处理过程了。这里使用了PreTranslateMessage()函数,在消息被发送到消息池里前,先进 行处理,于是程序通过。

【附函数介绍】- 网上收集

1. 函数原型(源自MSDN)
    virtual BOOL PreTranslateMessage(MSG* pMsg);
功能:
    重载该函数可以实现窗口消息在派发给窗口函数TranslateMessage()和DispatchMessage()之前的过滤.缺省的实现是完成加 速键的翻译.因为您必须在你的重载版本中调用CWinApp:PreTranslateMessage()函数.
    在MFC中,PreTranslateMessage()是虚函数,我们可以重载它来处理键盘和鼠标消息。
    在SDK中,这又有所不同,我们必须在回调函数中
      LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
处理消息,它和PreTranslateMessage起的作用是类似的。只是MFC封装的更好而已。

2. 说明
    该函数表示在消息处理(TranslateMessage()和DispatchMessage()等)前所作的操作,如果函数返回值为TRUE,那么消 息处理即终止,不会调用TranslateMessage()和DispatchMessage()来翻译和分发消息给相应的窗口;若返回值为 FALSE,才会调用翻译和分发消息函数。
    该函数是MFC消息控制流最具特色的地方,它是CWnd类的虚拟函数,通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流 出来。

    在win32程序中,关于消息有两种传递方式:
      a. MFC消息,MFC会把所有的消息一条条放到一个AFX_MSG_MAP_ENTRY结构中,形成一个数组,该数组存放了所有的消息和与它们相关的参数。 也可以说是放到消息队列里去。
      b. 采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息。
    这两种方式中只有第一种(穿过消息队列的消息)才受PreTranslateMessage()影响,第二种消息并不会理睬 PreTranslateMessage()的存在。

3. 其他
    一、是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数 的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。
    二、传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理。例如可以在该函数 中使用(pMsg->wParam == VK_RETURN)来拦截回车键。
    三、在WindowProc里不能处理WM_CHAR消息。(WindowProc函数见MFC消息响应机制一文)
    四、SetWindowText会发送WM_CHAR给窗口。
    五、PeekMessage和GetMessage的区别:
        GetMessage在没有消息的时候等待消息,效率低。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 CUserDlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYDOWN) //判断是否有按键按下 { switch(pMsg->wParam) { case VK_DOWN: //表示是方向键中的向下的键 // code here ... break; case VK_UP: //表示是方向键中的向上的键 // code here ... break; default: break; } } }

你可能感兴趣的:(技术研究)