-
CFrameWnd
鎖定
- 外文名
- CFrameWnd
- 用 途
- 創建應用程序的主窗口
- 使用範圍
- 單文檔界面(SDI)
CFrameWnd簡介
該類定義了兩個成員函數用於創建主窗口,即Create()和LoadFrame()。前者主要通過CWnd::CreateEx()創建窗口;而後者首先組織參數,再調用前者。它們的定義如下:
BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext)
{
/*可見,參數列表與CWnd::Create()稍有不同。因為目的是創建主窗口,所以第6個參數要求菜單資源名*/
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
//搜索包含該菜單資源的實例(當前進程或者按進行裝入的DLL)
HINSTANCE hInst = AfxFindResourceHandl(lpszMenuName, RT_MENU);
//裝入菜單資源
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE0(“Warning: failed to load menu for CFrameWnd.\n”);
PostNcDestroy(); //perhaps delete to C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; //存儲窗口標題,以備後用(如刷新顯示)
// 調用CWnd::CreateEx()
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right – rect.left, rect,bottom – rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
if (hMenu != NULL)
DestroyMenu(hMenu); //如果創建失敗,釋放菜單資源
return FALSE;
}
return TRUE;
}
BOOL CFrameWnd::LoadFrame(UNIT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
{
/*主窗口的菜單、圖標、加速鍵、及標題都以nIDResource標識。除創建窗口外,還要做許多工作,如設置幫助上下文ID、裝入加速鍵、初始化子窗口。所以在文檔/視圖框架程序中,總是使用LoadFrame()創建主窗口。*/
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxEXtractSubString(m_strTitle, strFullString, 0); //取得窗口標題
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
//裝入圖標,註冊窗口類
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
LPCTSTR lpszTitle = m_strTitle;
//調用CFrameWnd::Create()
if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
return FALSE;
//存儲菜單句柄
ASSERT(m_hWnd != NULL);
m_hMenuDefault = ::GetMenu(m_hWnd);
//裝入加速鍵
LoadAccelTable(MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) //初始化子窗口
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}
由於LoadFrame()的形能簡潔,在創建窗口的同時,完成許多主窗體的初始化工作。所以,如果以CFrameWnd為程序主窗體,一般通過LoadFrame()創建。如果要使用CFrameWnd 創建簡單化的主窗體或子窗體,可調用Create()。
在文檔視圖支持的SDI程序中,主框架窗是在文檔模板中應用CDocTemplate::CreateNewFrame()創建的。在該函數中,首先動態創建CFrameWnd對象,再調用對象的LoadFrame()成員。由於在CFrameWnd::PostNcDestroy()中清除了當前對象,所以儘管CFrameWnd對象慣於在堆中構造,卻不必關心它的釋放。例如:
void CFrameWnd::PostNcDestroy()
{
delete this;
}
CFrameWnd應用
CFrameWnd視圖
視圖是主框架窗口的一個ID為AFX_IDW_PANE_FIRST,帶有邊框的子窗口,這個主框架窗口是由CFrameWnd類封裝並創建的。顯然,視圖作為其子窗口,也是由CFrameWnd創建的。成員函數CFrameWnd::OnCreateClient()用於創建視圖窗口,它是該類的WM_CREATE消息處理函數中被調用的。代碼如下:
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
{
/*pContext->m_pNewViewClass存儲視圖的運動時類信息的指針(CRuntimeClass*),可用於動態創建視圖*/
if (pContext != NULL && pContext->m_pNewViewClass != NULL)
{
//調用CFrameWnd::CreateView()創建視圖
if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)
return FALSE;
}
return TRUE;
}
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
ASSERT(pContext != NULL);
ASSERT(pContext->m_pNewViewClass != NULL);
//應用運行類信息,動態創建視圖對象
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
if (pView == NULL)
{
TRACE1(“Warning: Dynamiccreateof view type %hs failed.\n”, pContext->m_pNewViewClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CWnd, pView);
//使用已經創建的視圖對象創建視圖窗口
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, nID, pContext))
{
TRACE0(“Warning: could notcreateview for frame.\n”);
return NULL; //can’t continue without a view
}
//根據視圖窗口的邊界風格調整框架窗口風格
if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
{
//如果視圖已經設置了凹陷邊框,去除主窗口的凹陷邊框
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
一個主窗口可能包含多個視圖,它們或者是通過CSpliterWnd在客户區拆分創建的,或者是直接在客户區以子窗口形式創建。框架規定只能有一個活動視圖,如果不使用拆分,同時只能顯示一個視圖。在主框架窗口創建後(視圖也已創建),一般要調用CFrameWnd::InitialUpdateFrame()進行初始化,該函數首先設置第一視圖(ID為AFX_IDW_PANE_FIRST)為活動視圖,然後向所有視圖發送初始化消息,確保每個視圖CView::OnInitialUpdate()被調用。
可以調用CFrameWnd::SetActiveView()及CFrameWnd::GetActiveView()設置或取得活動視圖。在設置活動視圖後,應該將活動視的ID切換為AFX_IDW_PANE_FIRST,因為有些操作是隻針對第一視圖的。例如,只有第一視圖才能與控制條爭奪主窗口客户區的空間,所以其他視圖無法在主框架窗口中正常顯示(如果不使用拆分)。
CFrameWnd控制條
主框架窗口的直觀特點是被豐富的控制條裝飾的,如工具條、狀態條等,它們都派生於基類CControlBar。當鼠標移到工具條或某菜單項區域時,相應的提示信息會在狀態欄顯示或以Tip形式彈出;沒有建立消息映射的命令會自動禁止;客户區發生變化時視圖和控制條會自動排列。這一切都是CFrameWnd封裝的功能。下面列舉幾個重要的控制條操作函數。
EnableDocking(): 允許控制條在自己的客户區依靠。
DockControlBar(): 將控制條依靠在客户區周邊。
FloatControlBar(): 將控制條浮動在屏幕上,而不是依靠在客户區。
ShowControlBar(): 顯示或隱藏控制條。
SaveBarState(): 將所有控制條的狀態存入初始化文件或註冊表。
LoadBarState(): 從初始化文件或註冊表中恢復所有控制條狀態。
GetDockState(): 將控制條狀態信息存入一個CDockState對象。
SetDockState(): 從一個CDockState對象中恢復控制條狀態。
SetMessageText(): 在狀態欄的第一個面板區域顯示一個信息串。
CFrameWnd命令消息
命令消息是指菜單、工具欄、加速鍵及命令按鈕向其所在窗口發送的WM_COMMAND消息。主框架窗口通常包含應用程序的系統主菜單和工具欄,而加速鍵往往在LoadFrame()中裝入主窗口,它們都要向主窗口發送命令消息。
命令消息與窗口消息(除WM_COMMAND之外,前綴是WM_的消息)不同,窗口消息與某一窗口(句柄)緊密相關,應該由接收消息的窗口來處理;而命令消息往往與具體的窗口無關,只是為本程序完成一個功能操作。主框架窗口的系統菜單(工具按鈕)尤其如此,某一個主菜單命令在其他窗口中(如視圖)或在其他模塊中(如文檔)處理也許更合理。為了解決這個矛盾,CFrameWnd實現了分發命令消息的機制,它能夠將本窗口收到的命令消息分發給視圖、文檔和應用類。
CCmdTarget類定義了一個OnCmdMsg()虛擬函數,用於處理命令消息,派生類可以重載它,實現自己的命令消息處理方式。是的,CFrameWnd的命令消息分發機制就是通過重載這個函數實現的。該函數的代碼如下:
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
//首先將命令消息傳給活動視圖
CView* pView = GetActiveView();
//如果袖圖沒有處理,它將傳送命令消息給關聯的文檔對象
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE; //視圖或文檔已經處理該命令,返回
//視圖或文檔沒有處理該消息,即沒有建立該命令的消息映射,下面由主窗口本身處理
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE; //主窗口已處理
//主窗口沒有處理,最後嘗試應用類
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE; //最終沒有處理該命令消息,返回false,該消息由默認過程處理
}
最後,讀者要注意這樣一個事實:主窗口直接調用視圖(間接調用文檔)、應用類的OnCmdMsg()虛函數處理命令消息,並沒有通過SendMessage()或PostMessage()將命令消息轉發。而OnCmdMsg()僅在類中搜索消息映射表,查找該命令的處理函數,找不到則返回false。所以視圖類只有通過消息映射,才能處理主窗口轉發的命令消息,如果使用CView::WindowProc()捕捉該類消息,會一無所獲。
CFrameWnd消息處理
為了管理控制條和視圖,CFrameWnd為幾個窗口消息建立了消息映射,專門進行處理。
OnInitMenuPopup(): 處理WM_INITMENUPOPUP消息,設置彈出菜單的各項目的啓用/禁止狀態。
OnEnterIdle(): 處理WM_ENTERIDLE消息,設置狀態條的空閒時提示信息。
OnMenuSelect(): 處理WM_MENUSELECT消息,當某菜單項被選擇時更新狀態條提示。
OnToolTipText(): 處理TTN_NEEDTEXT通知消息,顯示工具條的工具提示。
OnUpdateKeyIndicator(): 更新狀態條的鍵盤狀態指示器信息。
OnUpdateControlBarMenu(): 更新控制條的啓用/禁止狀態,如工具條按鈕。
OnSize(): 處理WM_SIZE消息,調用RecalcLayout()排列客户區控件及視圖。
OnHScroll(): 處理WM_HSCROLL消息,滾動視圖。
OnVScroll(): 處理WM_VSCROLL消息,滾動視圖。
OnClose(): 處理WM_CLOSE消息,存儲並關閉文檔。
CFrameWnd成員
m_bAutoMenuEnable | 自動控制使菜單項目可用或無效 |
rectDefault | 當構造一個CFrameWnd對象時傳遞此靜態CRect作為參數,使Windows選擇窗體的初始大小和位置 |
CFrameWnd | 構造一個CFrameWnd對象 |
初始化
Create | 調用以構造和初始化一個與CFrameWnd對象有關的Windows框架窗口 |
調用以從資源信息中動態構造一個框架窗口 | |
LoadAccelTable | 裝入一個加速器表格 |
復位控件條設置 | |
存儲控件條設置 | |
顯示控件條 | |
在主窗口中停靠框架窗口 | |
GetDockState | 獲取框架窗口的停靠狀態 |
操作
ActivateFrame | 使框架對用户可視並可用 |
InitialUpdateFrame在 | 調用的框架窗中使OnInitialUpdate成員函數屬於所有視圖 |
返回活動CFrameWnd對象 | |
SetActiveView | 設置活動CView對象 |
返回活動CView對象 | |
CreateView | 在框架中構造一個非CView派生的視圖 |
返回活動CDowment對象 | |
GetControlBar | 返回控件條 |
GetMessageString | 獲得與命令ID相符的消息 |
IsTracking | 確定分隔條是否正在移動 |
SetMessageText | 設置標準狀態條的文本 |
允許一個控件條停靠 | |
DockControlBar | 停靠一個控件條 |
FloatControlBar | 浮動一個控件條 |
將框架窗口設置為模態 | |
EndModalState | 結束框架窗口的模態狀態,用BeginModalState使無效的窗口可用 |
返回一個表明框架窗口是否處於模態狀態 | |
ShowOwnedWindows | 顯示所有CFrameWnd對象的後代窗口 |
重新設置CFrameWnd對象的控件條的位置 |
可重載函數
OnCreateClient | 為框架構造一個用户窗口 |
OnSetPreviewMode | 設置應用的主框架成為或退出預打印模式 |
GetMessageBar | 返回一個屬於框架窗口的狀態條指針 |
NegotiateBorderSpace | 調整框架窗口中的邊框空白 |
命令處理
OnContextHelp | 處理相應項的SHIFT+F1幫助 |
- 詞條統計
-
- 瀏覽次數:次
- 編輯次數:12次歷史版本
- 最近更新: 城_time