?? mfc
字號:
<P align=justify>layout.rect.bottom -= lpRectParam->bottom;</P>
<P align=justify>}</P>
<P align=justify>//基于layout.rect表示的客戶尺寸計算出窗口尺寸</P>
<P align=justify>pLeftOver->CalcWindowRect(&layout.rect);</P>
<P align=justify>//導致函數::DeferWindowPos的調用</P>
<P align=justify>AfxRepositionWindow(&layout, hWndLeftOver,
&layout.rect);</P>
<P align=justify>}</P>
<P align=justify></P>
<P align=justify>//給所有的窗口設置尺寸、位置(size and layout)</P>
<P align=justify>if (layout.hDWP == NULL ||
!::EndDeferWindowPos(layout.hDWP))</P>
<P align=justify>TRACE0("Warning: DeferWindowPos failed - low system
resources.\n");</P>
<P align=justify>}</P>
<P align=justify>RepositionBars用來改變客戶窗口中控制條的尺寸大小或者位置,其中:</P>
<P align=justify>參數1和參數2定義了需要重新放置的子窗口ID的范圍,一般是0到0xFFFF。</P>
<P
align=justify>參數3指定了一個子窗口ID,它擁有客戶窗口剩下的空間,一般是AFX_IDW_PANE_FIRST,表示視的窗口ID。</P>
<P
align=justify>參數4指定了操作類型,缺省是CWnd::ReposDefault,表示執行窗口放置操作,參數5不會用到;若取值CWnd::ReposQuery,則表示嘗試進行窗口放置(Layout)
,但最后不執行這個操作,只是把參數5初始化成客戶區的尺寸大小;若取值CWnd::ReposExtra,則把參數5的值加到參數2表示的子窗口的客戶區域,并執行窗口放置操作。</P>
<P align=justify>參數6表示傳遞給函數的可用窗口客戶區的尺寸,如果空則使用窗口客戶區尺寸。</P>
<P align=justify>如果執行layout操作的話,該函數的核心處理就是:</P>
<P
align=justify>首先,調用::BeginDeferWindowPos初始化一個Windows內部的多窗口位置結構(Multiple-window
- position structure)hDWP;</P>
<P
align=justify>然后,讓各個子窗口逐個調用::DeferWindowPos,更新hDWP。在調用::DeferWindowPos之前,要作一個確定子窗口大小的工作。這些工作通過給各個控制子窗口發送消息WM_SIZEPARENT來完成。</P>
<P
align=justify>控制子窗口通過函數OnSizeParent響應WM_SIZEPARENT消息,先確定自己的尺寸,然后,如果需要進行窗口布置(WM_SIZEPARENT消息參數lParam包含了一個非空的HDWP結構(lpLayout->hDWP)),則OnSizeParent將調用AfxRepositionWindow函數計算本控制窗口的位置,結果保存到hDWP中。</P>
<P
align=justify>在所有的控制窗口尺寸確定之后,剩下的留給窗口hWndLeftOver(如果存在的話)。確定了hWndLeftOver的大小之后,調用AfxRepositionWindow函數計算其位置,結果保存到hDWP中。</P>
<P align=justify>上面提到的函數AfxRepositionWindow間接調用了::DeferWindowPos。</P>
<P align=justify>最后,::EndDeferWindowPos,使用hDWP安排所有子窗口的位置和大小。</P>
<P align=justify></P>
<P
align=justify>至于其他函數,如OnSizeparent、OnWindowPosChanging、CalcWindowRect,這里不作進一步的分析。</P>
<P align=justify></P>
<LI><A name=_Toc452641012></A><A
name=_Toc457299146></A><B>工具條、狀態欄和邊框窗口的接口</B>
<P></P>
<OL>
<P align=justify>
<LI><B><A name=_Toc457299147></A>應用程序在狀態欄中顯示信息</B>
<P></P></LI></OL></LI></OL></OL></OL>
<P
align=justify>MFC內部通過給邊框窗口發送消息WM_SETMESSAGESTRING、WM_POPMESSAGESTRING的方式在狀態欄中顯示信息。這兩個消息在afxpriv.h里頭定義。</P>
<P
align=justify>WM_SETMESSAGESTRING消息表示在狀態欄中顯示和某個ID對應的字符串信息或者指定的字符串信息,消息參數wParam指定了字符串資源ID,消息參數lParam指定了字符串指針,兩個消息參數只有一個有用。一般,一個命令ID對應了一個字符串ID,對應的字符串是命令ID的說明。</P>
<P align=justify>消息WM_POPMESSAGESTRING用來重新設置狀態欄。</P>
<P
align=justify>這兩個消息對應的消息處理函數分別是OnSetMessageString和OnPopMessageString,OnSetMessageString和OnPopMessageString分別實現如下:</P>
<OL>
<P align=justify>
<LI>OnSetMessageString
<P></P>
<P align=justify>LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM
lParam)</P>
<P align=justify>{</P>
<P align=justify>//最近一次被顯示的消息字符串IDS(一個消息對應的字符串)</P>
<P align=justify>UINT nIDLast = m_nIDLastMessage;</P>
<P align=justify>m_nFlags &= ~WF_NOPOPMSG;</P>
<P align=justify></P>
<P align=justify>//得到狀態欄</P>
<P align=justify>CWnd* pMessageBar = GetMessageBar();</P>
<P align=justify>if (pMessageBar != NULL)</P>
<P align=justify>{</P>
<P align=justify>LPCTSTR lpsz = NULL;</P>
<P align=justify>CString strMessage;</P>
<P align=justify></P>
<P align=justify>//設置狀態欄文本</P>
<P align=justify>if (lParam != 0) //指向一個字符串</P>
<P align=justify>{</P>
<P align=justify>ASSERT(wParam == 0); // can't have both an ID and a
string</P>
<P align=justify>lpsz = (LPCTSTR)lParam; // set an explicit string</P>
<P align=justify>}</P>
<P align=justify>else if (wParam != 0)//一個字符串資源IDS</P>
<P align=justify>{</P>
<P align=justify>//打印預覽時映射SC_CLOSE成AFX_IDS_PREVIEW_CLOSE;</P>
<P align=justify>if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc !=
NULL)</P>
<P align=justify>wParam = AFX_IDS_PREVIEW_CLOSE;</P>
<P align=justify></P>
<P align=justify>//得到資源ID所標識的字符串</P>
<P align=justify>GetMessageString(wParam, strMessage);</P>
<P align=justify>lpsz = strMessage;</P>
<P align=justify>}</P>
<P align=justify>//在狀態欄中顯示文本</P>
<P align=justify>pMessageBar->SetWindowText(lpsz);</P>
<P align=justify></P>
<P align=justify>// 根據最近一次選擇的消息更新狀態條所屬窗口的有關記錄</P>
<P align=justify>CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame();</P>
<P align=justify>if (pFrameWnd != NULL)</P>
<P align=justify>{</P>
<P align=justify>//記錄最近一次顯示的消息字符串</P>
<P align=justify>pFrameWnd->m_nIDLastMessage = (UINT)wParam;</P>
<P align=justify>//記錄最近一次Tracking的命令ID和字符串IDS</P>
<P align=justify>pFrameWnd->m_nIDTracking = (UINT)wParam;</P>
<P align=justify>}</P>
<P align=justify>}</P>
<P align=justify></P>
<P align=justify>m_nIDLastMessage = (UINT)wParam; // new ID (or 0)</P>
<P align=justify>m_nIDTracking = (UINT)wParam; // so F1 on toolbar buttons
work</P>
<P align=justify>return nIDLast;</P>
<P align=justify>}</P>
<P
align=justify>OnSetMessageString函數直接或者從ID從字符串資源中得到字符串指針。如果是從ID得到字符串指針,則函數GetMessageString被調用。</P>
<P
align=justify>和命令ID對應的字符串由兩部分組成,前一部分用于在狀態欄顯示,后一部分用于Tooltip顯示,分隔符號是“\n”。例如,字符串ID_APP_EXIT(對應“退出”菜單、按鈕)是“Exit
Application\nExit”,當鼠標落在“退出”按鈕上時,狀態欄顯示“Exit
Application”,Tooltip顯示“Exit”。根據這種格式,GetMessageString分離出第一部分的文本信息。至于第二部分的用途將在討論Tooltip的章節將用到。</P>
<P
align=justify>得到了字符串之后,OnSetMessageString調用狀態欄的SetWindowText函數。SetWindowText導致消息WM_SETTEXT消息發送給狀態欄,狀態欄的消息處理函數OnSetText被調用,實際上等于調用了SetPaneText(0,
lpsz),即在狀態欄的第0格中顯示字符串lpsz的信息。對于工具欄來說,SetWindowText可以認為是SetPaneText(0,
lpsz)的簡化版本。</P>
<P
align=justify>順便指出,pMessageBar->GetParentFrame()返回主邊框窗口,即使pMessageBar指向漂浮的工具條。關于泊位和漂浮,見后面13.2.5節的描述。</P>
<P align=justify>關于OnSetText,其實現如下:</P>
<P align=justify>LRESULT CStatusBar::OnSetText(WPARAM, LPARAM lParam)</P>
<P align=justify>{</P>
<P align=justify>ASSERT_VALID(this);</P>
<P align=justify>ASSERT(::IsWindow(m_hWnd));</P>
<P align=justify></P>
<P align=justify>int nIndex = CommandToIndex(0); //返回0</P>
<P align=justify>if (nIndex < 0)</P>
<P align=justify>return -1;</P>
<P align=justify></P>
<P align=justify>return SetPaneText(nIndex, (LPCTSTR)lParam) ? 0 : -1;</P>
<P align=justify>}</P>
<P align=justify></P>
<LI>OnPopMessageString
<P></P></LI></OL>
<P align=justify>LRESULT CFrameWnd::OnPopMessageString(WPARAM wParam, </P>
<DIR>
<DIR>
<P align=justify>LPARAM lParam)</P></DIR></DIR>
<P align=justify>{</P>
<P align=justify>//WF_NOPOPMSG表示邊框窗口不處理WM_POPMESSAGESTRING</P>
<P align=justify>if (m_nFlags & WF_NOPOPMSG)</P>
<DIR>
<P align=justify>return 0;</P>
<P align=justify></P></DIR>
<P align=justify>//調用OnSetMessageString</P>
<P align=justify>return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);</P>
<P align=justify>}</P>
<P align=justify>一般,在清除狀態欄消息時,發送WM_POPMESSAGESTRING,通過消息參數wParam指定一個字符串資源,其ID
為AFX_IDS_IDLEMESSAGE,對應的字符串是“Ready”。</P>
<OL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc457299148></A><B>狀態欄顯示菜單項的提示信息</B>
<P></P>
<P
align=justify>狀態欄的一個重要作用是顯示菜單命令或者工具條按鈕的提示信息。本節討論如何顯示菜單命令的提示信息,關于工具條按鈕在這方面的討論見后面13.2.4.4章節。</P>
<P
align=justify>顯示菜單命令的提示信息,就是每當一個菜單項被選中之后,在狀態欄顯示該菜單的功能、用法等信息。這些信息以字符串資源的形式保存,字符串ID對應于菜單項的命令ID。</P>
<P
align=justify>所以,必須處理菜單選擇消息WM_MENUSELECT。CFrameWnd實現了消息處理函數OnMenuSelect,其實現如下:</P>
<P align=justify>void CFrameWnd::OnMenuSelect(UINT nItemID, </P>
<P align=justify>UINT nFlags, HMENU /*hSysMenu*/)</P>
<P align=justify>{</P>
<P align=justify>CFrameWnd* pFrameWnd = GetTopLevelFrame();</P>
<P align=justify>ASSERT_VALID(pFrameWnd);</P>
<P align=justify></P>
<P align=justify>//跟蹤被選中的菜單項</P>
<P align=justify>if (nFlags == 0xFFFF)</P>
<P align=justify>{</P>
<P align=justify>//取消菜單操作</P>
<P align=justify>m_nFlags &= ~WF_NOPOPMSG;</P>
<P align=justify>if (!pFrameWnd->m_bHelpMode)</P>
<P align=justify>m_nIDTracking = AFX_IDS_IDLEMESSAGE;</P>
<P align=justify>else</P>
<P align=justify>m_nIDTracking = AFX_IDS_HELPMODEMESSAGE;</P>
<P align=justify>//在狀態欄顯示</P>
<P align=justify>SendMessage(WM_SETMESSAGESTRING,
(WPARAM)m_nIDTracking);</P>
<P align=justify>ASSERT(m_nIDTracking == m_nIDLastMessage);</P>
<P align=justify></P>
<P align=justify>// update right away</P>
<P align=justify>CWnd* pWnd = GetMessageBar();</P>
<P align=justify>if (pWnd != NULL)</P>
<P align=justify>pWnd->UpdateWindow();</P>
<P align=justify>}</P>
<P align=justify>else</P>
<P align=justify>{</P>
<P align=justify>//選中分隔欄、Popup子菜單或者沒有選中一個菜單項</P>
<P align=justify>if (nItemID == 0 || nFlags &
(MF_SEPARATOR|MF_POPUP))</P>
<P align=justify>{</P>
<P align=justify>// nothing should be displayed</P>
<P align=justify>m_nIDTracking = 0;</P>
<P align=justify>}</P>
<P align=justify>else if (nItemID >= 0xF000 && nItemID <
0xF1F0) // max of 31 SC_s</P>
<P align=justify>{</P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -