?? mfc
字號:
<P align=justify>//系統菜單的菜單項被選中</P>
<P align=justify>m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);</P>
<P align=justify>ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST
&&</P>
<P align=justify>m_nIDTracking < AFX_IDS_SCFIRST + 31);</P>
<P align=justify>}</P>
<P align=justify>else if (nItemID >= AFX_IDM_FIRST_MDICHILD)</P>
<P align=justify>{</P>
<P align=justify>//如果選中的菜單項表示一個MDI子窗口</P>
<P align=justify>m_nIDTracking = AFX_IDS_MDICHILD;</P>
<P align=justify>}</P>
<P align=justify>else</P>
<P align=justify>{</P>
<P align=justify>//選中了一個菜單項</P>
<P align=justify>m_nIDTracking = nItemID;</P>
<P align=justify>}</P>
<P align=justify>pFrameWnd->m_nFlags |= WF_NOPOPMSG;</P>
<P align=justify>}</P>
<P align=justify></P>
<P align=justify>// when running in-place, it is necessary to cause a
message to</P>
<P align=justify>// be pumped through the queue.</P>
<P align=justify>if (m_nIDTracking != m_nIDLastMessage &&
GetParent() != NULL)</P>
<P align=justify>PostMessage(WM_KICKIDLE);</P>
<P align=justify>}</P>
<P
align=justify>OnMenuSelect的作用在于跟蹤當前選中的菜單項,把菜單項對應的ID保存在CFrameWnd的成員變量m_nIDTracking中。</P>
<P align=justify>如果菜單項沒有選中,或者選中的是一個子菜單,則設置nIDTracking為0。</P>
<P align=justify>如果選中的是系統菜單,則把系統菜單ID轉換成一個對應的命令ID;保存該值到nIDTracking中。</P>
<P
align=justify>如果選中的菜單是MDI子窗口創建時添加的(用來表示MDI子窗口),則轉換菜單ID為AFX_IDS_MDICHILD,所有對應MDI子窗口的菜單項都使用AFX_IDS_MDICHILD,保存該值到nIDTracking中。</P>
<P align=justify>其他情況,就是選中菜單項的ID,把它保存到nIDTracking中。</P>
<P align=justify></P>
<P
align=justify>跟蹤被選擇的菜單項并保存其ID在m_nIDTracking中,OnEnterIdle將用到m_nIDTracking。OnEnterIlde是消息WM_ENTERIDLE的處理函數,CFrameWnd的實現如下。</P>
<P align=justify>void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho)</P>
<P align=justify>{</P>
<P align=justify>CWnd::OnEnterIdle(nWhy, pWho);</P>
<P align=justify></P>
<P align=justify>//若不是因為菜單選擇進入該函數</P>
<P align=justify>//或者當前跟蹤到的菜單項ID是最近一次處理的,則返回</P>
<P align=justify>if (nWhy != MSGF_MENU || m_nIDTracking ==
m_nIDLastMessage)</P>
<P align=justify>return;</P>
<P align=justify></P>
<P align=justify>//將發送消息WM_SETMESSAGETEXT</P>
<P align=justify>//在狀態欄顯示m_nIDTracking對應的字符串</P>
<P align=justify>SetMessageText(m_nIDTracking);</P>
<P align=justify>ASSERT(m_nIDTracking == m_nIDLastMessage);</P>
<P align=justify>}</P>
<P
align=justify>當一個對話框或者菜單被顯示的時候,Windows發送WM_ENTERIDLE消息。消息參數wParam取值為MSGF_DIALOGBOX或者MSGF_MENU。前者表示顯示對話框時發送該消息,這時消息參數lParam表示對話框的句柄;后者表示顯示菜單時發送該消息,這時消息參數lParam表示菜單的句柄。</P>
<P
align=justify>經過消息映射,wParam的值傳遞給OnEnterIdle的參數nWhy,參數lParam的值傳給參數who。如果參數1取值為MSGF_MENU,并且OnEnterIdle最近一次在菜單顯示被調用時的菜單ID不同于這一次,則調用SetMessageText在狀態欄顯示對應ID命令的字符串,并且記錄當前菜單ID到變量m_nIDTracking中(見消息處理函數OnSetMessageText)。</P>
<P
align=justify>這樣,在菜單選擇期間,用戶選擇的菜單項ID被OnMenuSelect記錄,在消息WM_ENTERIDLE處理時在狀態欄顯示ID命令的提示。</P>
<P align=justify></P>
<LI><A name=_Toc457299149></A><B>控制條的消息分發處理</B>
<P></P></LI></OL></OL></OL></OL>
<P
align=justify>工具條(包括對話框工具條)是一個子窗口,它們可以響應各種消息。如果按標準的Windows消息和命令消息的分發途徑,一些消息不能送到擁有工具條的邊框窗口,因為這些消息都將被工具條(對話框工具條)處理掉。所以,CControlBar覆蓋了虛擬函數PreTranslateMessage和WindowProc以便實現特定的消息分發路徑。</P>
<OL>
<P align=justify>
<LI>WindowProc
<P></P>
<P align=justify>CControlBar 的WindowProc實現了如下的消息分發路徑:</P>
<P
align=justify>用戶對控制條的輸入消息或者分發給CControlBar及其派生類處理,或者送給擁有控制條的邊框窗口處理,或者送給Windows控制“窗口類”的窗口過程處理。</P>
<P align=justify>WindowProc的實現如下:</P>
<P align=justify>LRESULT CControlBar::WindowProc(UINT nMsg, </P>
<P align=justify>WPARAM wParam, LPARAM lParam)</P>
<P align=justify>{</P>
<P align=justify>ASSERT_VALID(this);</P>
<P align=justify></P>
<P align=justify>LRESULT lResult;</P>
<P align=justify>switch (nMsg)</P>
<P align=justify>{</P>
<P align=justify>//本函數處理以下消息</P>
<P align=justify>case WM_NOTIFY:</P>
<P align=justify>case WM_COMMAND:</P>
<P align=justify>case WM_DRAWITEM:</P>
<P align=justify>case WM_MEASUREITEM:</P>
<P align=justify>case WM_DELETEITEM:</P>
<P align=justify>case WM_COMPAREITEM:</P>
<P align=justify>case WM_VKEYTOITEM:</P>
<P align=justify>case WM_CHARTOITEM:</P>
<P align=justify>//首先,工具條處理上述消息,如果沒有處理,則接著給所屬邊框窗口處理</P>
<P align=justify>if (OnWndMsg(nMsg, wParam, lParam, &lResult))</P>
<P align=justify>return lResult;</P>
<P align=justify>else</P>
<P align=justify>return GetOwner()->SendMessage(nMsg, wParam, lParam);</P>
<P align=justify>}</P>
<P align=justify>}</P>
<P align=justify>// 最后,給基類CWnd,按缺省方式處理</P>
<P align=justify>lResult = CWnd::WindowProc(nMsg, wParam, lParam);</P>
<P align=justify>return lResult;</P>
<P align=justify>}</P>
<P
align=justify>從上述實現可以看出,對于case范圍內的一些消息,如WM_COMMAND、WM_NOTIFY等,控制條如果不能處理,則優先分發給其父窗口(邊框窗口)處理,然后進入缺省處理,對于其他消息直接調用基類CWnd的實現(缺省處理)。基于這樣的機制,可以把用戶對工具條按鈕或者對話框工具條內控制的操作解釋成相應的命令消息,執行對應的命令處理。</P>
<P
align=justify>對于工具條,當用戶選中某個按鈕時(鼠標左鍵彈起,消息是WM_LBUTTONUP),工具條窗口接收到WM_LBUTTONUP消息,該消息不在CControlBar::WindowProc特別處理的消息范圍內,于是進行缺省處理,也就是說,把該消息派發給控制條對應的Windows控制的窗口過程處理(即被MFC統一窗口過程所取代的原窗口過程),該窗口過程則把該消息轉換成一條命令消息WM_COMMAND,命令ID就是選中按鈕對應的ID,然后,發送該命令消息給擁有工具條的邊框窗口,導致相應的命令處理函數被調用。</P>
<P
align=justify>對于對話框工具條,當工具條的某個控制子窗口被選中之后,則產生一條命令通知消息WM_COMMAND,wParam是控制子窗口的ID。CControlBar::WindowProc處理該消息。WindowProc首先調用OnWndMsg把消息發送給對話框工具條或者對話框工具條的基類處理,如果沒有被處理的話,則OnWndMsg返回FALSE。接著,WindowPoc把命令消息傳遞給父窗口(邊框窗口)處理。由于工具條的控制窗口的ID對應的是命令ID,所以,這條WM_COMMAND消息傳遞給邊框窗口時,被解釋成一個命令消息,相應的命令處理函數被調用。</P>
<P align=justify></P>
<LI>PreTranslateMessage
<P></P></LI></OL>
<P
align=justify>CControlBar覆蓋PreTranslateMessage函數,主要是為了在光標落在工具條按鈕上時顯示FLYBY信息,并且讓對話框工具條過濾Dialog消息。</P>
<P align=justify>BOOL CControlBar::PreTranslateMessage(MSG* pMsg)</P>
<P align=justify>{</P>
<P align=justify>ASSERT_VALID(this);</P>
<P align=justify>ASSERT(m_hWnd != NULL);</P>
<P align=justify></P>
<P align=justify>//過濾Tooltip消息</P>
<P align=justify>if (CWnd::PreTranslateMessage(pMsg))</P>
<DIR>
<P align=justify>return TRUE; //是Tooltip消息,已經被處理</P>
<P align=justify></P></DIR>
<P align=justify>UINT message = pMsg->message;</P>
<P align=justify>//控制條的父窗口,對工具條和對話框工具條,總是創建它的邊框窗口</P>
<P align=justify>CWnd* pOwner = GetOwner();</P>
<P align=justify></P>
<P align=justify>//必要的話,在狀態條顯示工具欄按鈕的提示</P>
<P align=justify>if (((m_dwStyle & CBRS_FLYBY) ||</P>
<DIR>
<P align=justify>message == WM_LBUTTONDOWN || message == WM_LBUTTONUP)
&&</P>
<P align=justify>((message >= WM_MOUSEFIRST && message <=
WM_MOUSELAST) ||</P>
<P align=justify>(message >= WM_NCMOUSEFIRST && </P>
<DIR>
<P align=justify>message <= WM_NCMOUSELAST)))</P></DIR></DIR>
<P align=justify>{</P>
<DIR>
<P align=justify>_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();</P>
<P align=justify></P>
<P align=justify>//確認鼠標在工具欄的哪個按鈕上</P>
<P align=justify>CPoint point = pMsg->pt;</P>
<P align=justify>ScreenToClient(&point);</P>
<P align=justify>TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));</P>
<P align=justify>ti.cbSize = sizeof(TOOLINFO);</P>
<P align=justify>int nHit = OnToolHitTest(point, &ti);</P>
<P align=justify>if (ti.lpszText != LPSTR_TEXTCALLBACK)</P>
<DIR>
<P align=justify>free(ti.lpszText);</P></DIR>
<P align=justify>BOOL bNotButton =</P>
<DIR>
<P align=justify>message == WM_LBUTTONDOWN && (ti.uFlags &
TTF_NOTBUTTON);</P></DIR>
<P align=justify>if (message != WM_LBUTTONDOWN &&
GetKeyState(VK_LBUTTON) < 0)</P>
<DIR>
<P align=justify>nHit = pThreadState->m_nLastStatus;</P>
<P align=justify></P></DIR>
<P align=justify>//更新狀態欄的提示信息</P>
<P align=justify>if (nHit < 0 || bNotButton)</P>
<P align=justify>{</P>
<DIR>
<P align=justify>if (GetKeyState(VK_LBUTTON) >= 0 || bNotButton)</P>
<P align=justify>{</P>
<P align=justify>SetStatusText(-1);</P>
<P align=justify>KillTimer(ID_TIMER_CHECK);</P>
<P align=justify>}</P></DIR>
<P align=justify>}</P>
<P align=justify>else</P>
<P align=justify>{</P>
<DIR>
<P align=justify>if (message == WM_LBUTTONUP)</P>
<P align=justify>{</P>
<DIR>
<DIR>
<P align=justify>SetStatusText(-1);</P>
<P align=justify>ResetTimer(ID_TIMER_CHECK, 200);</P></DIR></DIR>
<P align=justify>}</P></DIR>
<P align=justify>else</P>
<P align=justify>{</P>
<DIR>
<P align=justify>if ((m_nStateFlags & statusSet) || GetKeyState(VK_LBUTTON)
< 0)</P>
<P align=justify>SetStatusText(nHit);</P></DIR>
<P align=justify>else if (nHit != pThreadState->m_nLastStatus)</P>
<DIR>
<P align=justify>ResetTimer(ID_TIMER_WAIT, 300);</P></DIR>
<P align=justify>}</P></DIR>
<P align=justify>}</P>
<P align=justify>pThreadState->m_nLastStatus = nHit;</P>
<P align=justify>}</P>
<P align=justify></P>
<P align=justify>// don't translate dialog messages when in Shift+F1 help
mode</P>
<P align=justify>CFrameWnd* pFrameWnd = GetTopLevelFrame();</P>
<P align=justify>if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)</P>
<DIR>
<P align=justify>return FALSE;</P>
<P align=justify></P></DIR>
<P align=justify>//在IsDialogMessage之前調用邊框
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -