• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            面對現實,超越自己
            逆水行舟,不進則退
            posts - 269,comments - 32,trackbacks - 0

            PreTranslateMessage作用和使用方法

                     PreTranslateMessage是消息在送給TranslateMessage函數之前被調用的,絕大多數本窗口的消息都要通過這里,比較常用,當需要在MFC之前處理某些消息時,常常要在這里添加代碼.  


                    
            MFC消息控制流最具特色的地方是CWnd類的虛擬函數PreTranslateMessage(),通過重載這個函數,可以改變MFC的消息控制流程,甚至可以作一個全新的控制流出來。只有穿過消息隊列的消息才受PreTranslateMessage()影響,采用SendMessage()或其他類似的方式向窗口直接發送的而不經過消息隊列的消息根本不會理睬PreTranslateMessage()的存在。 


                   是否調用TranslateMessage()DispatchMessage()是由一個名稱為PreTranslateMessage()函數的返回值決定的,如果該函數返回TRUE,則不會把該消息分發給窗口函數處理。
                   傳給PreTranslateMessage()的消息是未經翻譯過的消息,它沒有經過TranslateMessage()處理。可以在該函數中使用(pMsg->wParam==VK_RETURN)來攔截回車鍵。wParam中存放的是鍵盤上字符的虛擬碼。

            PeekMessage
            GetMessage的區別:
            GetMessage
            在沒有消息的時候等待消息,cpu當然低
            PeekMessage
            沒有消息的時候立刻返回,所以cpu占用率高。
            因為游戲不能靠windows消息驅動,所以要用PeekMessage(); 
                 PretranslateMessage
            的實現,不得不談到MFC消息循環的實現。MFC通過CWinApp類中的Pumpmessage函數實現消息循環,但是實際的消息循環代碼位于CWinThread中,CWinApp只是從CWinThread繼承過來。其簡化后的代碼大概如下: 

             1   BOOL CWinThread::PumpMessage() 
             2   { 
             3   _AFX_THREAD_STATE *pState = AfxGetThreadState(); 
             4    
             5   ::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL)) 
             6    
             7   if (!AfxPreTranslateMessage(&(pState->m_msgCur))) 
             8   { 
             9   ::TranslateMessage(&(pState->m_msgCur)); 
            10   ::DispatchMessage(&(pState->m_msgCur)); 
            11   } 
            12   return TRUE; 
            13   }
                  

                  可以看到,PumpMessage在實際的TranslateMessageDispatchMessage發生之前會調用AfxPreTranslateMessageAfxPreTranslateMessage又會調用CWnd::WalkPreTranslateTree(雖然也會調用其他函數,但是這個最為關鍵),其代碼如下:

             1 BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg) 
             2   { 
             3   ASSERT(hWndStop == NULL || ::IsWindow(hWndStop)); 
             4   ASSERT(pMsg != NULL); 
             5    
             6   // walk from the target window up to the hWndStop window checking 
             7   // if any window wants to translate this message 
             8    
             9   for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd)) 
            10   { 
            11   CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 
            12   if (pWnd != NULL) 
            13   { 
            14   // target window is a C window 
            15   if (pWnd->PreTranslateMessage(pMsg)) 
            16   return TRUE; // trapped by target window (eg: accelerators) 
            17   } 
            18    
            19   // got to hWndStop window without interest 
            20   if (hWnd == hWndStop) 
            21   break
            22   } 
            23   return FALSE; // no special processing 
            24   } 
                

            可以看到,代碼還是很直接的。從接受到消息的窗口層層往上遍歷,并調用PretranslateMessage看是否返回TRUE,是則結束,否則繼續。
              這里有一個地方非常關鍵:CWnd *pWnd = CWnd::FromHandlePermanent(hWnd) 這一句代碼從當前AfxModuleThreadState拿到Permanent句柄表,從而找到hWnd對應的CWnd MFCPreTranslateMessageGetMessage(...)函數的下一級操作,即GetMessage(...)從消息隊列中獲取消息后,交由PreTranslateMessage()處理,若其返回FALSE則再交給TranslateMessageDispatchMessage處理(進入WindowProc);  
            如果用SendMessage,   則消息直接交到WindowProc處理,所以GetMessage不會取得SendMessage的消息,當然PreTranslateMessage也就不會被調用。   [Page]
            如果用PostMessage,則消息進入消息隊列,由GetMessage取得,PreTranslateMessage就有機會進行處理。


            windows
            消息處理機制是這樣的:  
                  
            首先系統(也就是windows)把來自硬件(鼠標,鍵盤等消息)和來自應用程序的消息 放到一個系統消息隊列中去而應用程序需要有自己的消息隊列,也就是線程消息隊列,每一個線程有自己的消息隊列,對于多線程的應用程序就有和線程數目相等的線程消息隊列.  
              windows
            消息隊列把得到的消息發送到線程消息隊列,線程消息隊列每次取出一條消息發送到指定窗口,不斷循環直到程序退出實現的.這個循環就是靠消息環(while(GetMessage()) TranslateMessage();DispatchMessage();.GetMessage()只是從線程消息中取出一條消息,TranslateMessage()virtue key消息轉化成character消息,如VK_F1會轉化成WM_HELP,DispatchMessage  則把取出的消息發送到目的窗口.如果收到WM_CLOSE消息則結束循環,發送postqiutmessage(0),處理WM_DESTROY毀窗口!

             while (GetMessage(&msg, NULL, 0, 0))          //C++ code
             {  
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
             }

             win32 程序中,關于消息有兩種傳遞方式:

            1.      MFC 消息, MFC 會把所有的消息一條條放到一個 AFX_MSGMAP_ENTRY 結構中,形成一個數組,該數組存放了所有的消息和與

            它們相關的參數。也可以說是放到消息隊列里去。

            2.      采用 SendMessage() 或其他類似的方式向窗口直接發送的而不經過消息隊列的消息。


            這兩種方式中只有第一種(穿過消息隊列的消息)才受 PreTranslateMessage() 影響,

            第二種消息并不會理睬 PreTranslateMessage() 的存在。

            1)      是否調用 TranslateMessage() 和 DispatchMessage() 是由一個名稱為 PreTranslateMessage() 函數的返回值決定的,如果該函數返回

             TRUE ,則不會把該消息分發給窗口函數處理。

            2)      傳給 PreTranslateMessage() 的消息是未經翻譯過的消息,它沒有經過 TranslateMessage() 處理。可以在該函數中使用 

            (pMsg->wParam==VK_RETURN) 來攔截回車鍵。

            3)      在 WindowProc 里不能處理 WM_Char 消息。( WindowProc 函數見 MFC 消息響應機制一文)

            4)      SetWindowText 會發送 WM_Char 給窗口。

            5)      PeekMessage 和 GetMessage 的區別:

            6)      GetMessage 在沒有消息的時候等待消息, cpu 當然低

            7)      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() 函數的小程序示例:

              1 BOOL CSearchuserDlg::PreTranslateMessage(MSG* pMsg) 
              3 {
              5      if (pMsg->message==WM_KEYDOWN)  // 判斷是否有按鍵按下 
              7      { 
              9            switch (pMsg->wParam) 
             11            { 
             13            case VK_DOWN:     // 表示是方向鍵中的向下的鍵
             15                 //add handle code here
             17                 break ;
             19            case VK_UP:      // 表示是方向鍵中的向上的鍵
             21                 //add handle code here
             23                 break ;
             25            default :
             27                 break ;
             29            }
             31      }
             33 } 
             36 
             37 BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
             38 {
             39      // TODO: Add your specialized code here and/or call the base class 
             41      // 按鍵相應
             42      if (pMsg->message == WM_KEYDOWN)
             43      {
             44            if (pMsg->wParam == VK_DOWN)
             45            {
             46                 // 向下鍵按下
             47            }
             48            else if (pMsg->wParam == VK_RIGHT)
             49            {
             50                 // 向右鍵按下
             51            }
             52            else if (pMsg->wParam == VK_LEFT)
             53           {
             54                 // 向左鍵按下
             55            }
             56            else if (pMsg->wParam == VK_UP)
             57            {
             58                 // 向上鍵按下
             59            }
             60            else if (pMsg->wParam == VK_SHIFT)
             61            {
             62                 //VK_LSHIFT 為左 Shift 鍵按下
             63                 //Shift 鍵按下
             64            }
             65            else if (pMsg->wParam == VK_CONTROL)
             66            {
             67                 //Ctrl 鍵按下
             68            }
             69            else if (pMsg->wParam>=VK_NUMPAD0 && pMsg->wParam<=VK_NUMPAD9)
             70            {
             71                 // 小鍵盤數字鍵按下
             72            }
             73            else if (pMsg->wParam>=0x30 && pMsg->wParam<=0x39)
             74            {
             75                 // 數字鍵按下 ( 我記得不能使用 VK_0)
             76            }
             77            else if (pMsg->wParam>=0x41 && pMsg->wParam<=0x5A)
             78            {
             79                 // 鍵盤字母鍵按下 ( 我記得不能使用 VK_A)
             80            }
             81            else if (pMsg->wParam == VK_BACK)
             82            {
             83                 // 退格鍵按下
             84            }
             85            else if (pMsg->wParam == VK_DELETE)
             86            {
             87                 // 刪除鍵按下
             88            }
             89            else if (pMsg->wParam == VK_F1)
             90            {
             91                 //F1 鍵按下
             92            }
             93 
             94            //return true;  // 使消息不再進行處理
             95      }
             96 
             97      if (pMsg->message == WM_KEYUP)
             98      {
             99            if (pMsg->wParam == VK_SHIFT)
            100            {
            101                 //Shift 鍵彈起
            102            }
            103            else if (pMsg->wParam == VK_CONTROL)
            104            {
            105                 //Ctrl 鍵彈起
            106            }
            107            //return true;  // 使消息不再進行處理
            108      }
            109 
            110      return CDialog::PreTranslateMessage(pMsg);
            111 }
            112 
            113 // 同時按下 ctrl 鍵
            114 BOOL   CDemo_DevStudioView::PreTranslateMessage(MSG*   pMsg)   // 根據鍵盤上的按鍵對圖形進行相應的操作  
            116 
            117      if (pMsg->message==256)   //   256 有鍵按下, 46   DEL 鍵  
            118      { 
            119            switch (pMsg->wParam)   
            120            { 
            121                 /// 向左鍵被按下    
            122            case    37
            123                 { 
            124                      // 同時按下了 CTRL 鍵  
            125                      if (::GetKeyState(VK_CONTROL)       <       0)       
            126                      {       
            127                      } 
            128                 } 
            129            } 
            130      }
            131 }
            posted on 2012-09-05 12:48 王海光 閱讀(1737) 評論(0)  編輯 收藏 引用 所屬分類: MFC
            亚洲天堂久久精品| 久久这里只有精品18| 日韩久久久久久中文人妻| 久久九九免费高清视频| 国内精品久久久久影院免费| 国产三级久久久精品麻豆三级| 亚洲中文字幕无码久久2020| 伊人久久大香线蕉av不变影院| 思思久久精品在热线热| 久久久久国产精品嫩草影院| 无码专区久久综合久中文字幕 | 国产精品久久久久久一区二区三区| 久久久久久久波多野结衣高潮| 国产精品99久久久久久宅男小说| 免费精品久久天干天干| 国内精品人妻无码久久久影院导航| 无码人妻久久一区二区三区| 久久精品亚洲日本波多野结衣 | 精品熟女少妇av免费久久| 浪潮AV色综合久久天堂| 欧美精品一本久久男人的天堂| 久久久中文字幕| 色诱久久av| 色欲久久久天天天综合网| 2021久久国自产拍精品| 久久精品女人天堂AV麻| 久久亚洲熟女cc98cm| 久久99久久99小草精品免视看| 久久久久亚洲爆乳少妇无| 久久中文字幕精品| 国产精品9999久久久久| 久久久网中文字幕| 色诱久久久久综合网ywww | 亚洲综合熟女久久久30p| 久久亚洲欧美国产精品| 久久电影网| 午夜人妻久久久久久久久| 久久国产香蕉一区精品| 亚洲欧美日韩中文久久| 久久青青草原精品国产软件| 亚洲精品无码久久久久久|