首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

MFC 核心機制深度解析(五之二):SDI/MDI 框架窗口、視圖創建與初始化全流程

     編輯:關於VC++

承接上篇,本文深入剖析 MFC 文檔/視圖架構中最複雜的環節:**框架窗口加載、視圖創建、初始化更新、激活顯示** 的完整調用鏈。通過源碼級流程圖解,揭示 LoadFrame、OnCreate、OnCreateClient、CreateView、InitialUpdateFrame、OnInitialUpdate、ActivateFrame 等關鍵虛擬函數的協作機制,並對比 SDI 與 MDI 的異同,助你精準掌控窗口生命周期。

一、 SDI 框架窗口創建:從 LoadFrame 到 OnCreateClient

1. CFrameWnd::LoadFrame 核心流程

BOOL CFrameWnd::LoadFrame(UINT nIDResource,
    DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
    CWnd* pParentWnd = NULL,
    CCreateContext* pContext = NULL)
  • 參數解析:資源 ID(菜單/圖標/加速鍵/字符串)、窗口風格、父窗口、創建上下文(含視圖類信息、文檔指針、文檔模板指針)。
  • 關鍵步驟:
    1. 註冊兩個窗口類:框架窗口類、視圖窗口類(AfxRegisterWndClass)。
    2. 調用虛擬函數 Create → 內部 ::CreateWindowEx 創建 HWND,將 pContext 作為 lpCreateParams 傳入。
    3. 窗口創建觸發 WM_NCCREATE/WM_CREATE,進入 OnCreate。

2. CFrameWnd::OnCreate → OnCreateClient

int CFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
    CCreateContext* pContext = (CCreateContext*)lpCreateStruct->lpCreateParams;
    return OnCreateHelper(lpCreateStruct, pContext);
}

OnCreateHelper 核心邏輯:

  1. 調用 CWnd::OnCreate(基類處理)。
  2. 調用虛擬函數 OnCreateClient(lpCreateStruct, pContext) —— SDI 默認實現調用 CreateView 創建視圖。
  3. 發送 WM_SETMESSAGESTRING 設置狀態欄「Ready」。
  4. 調用 RecalcLayout 佈局工具欄/狀態欄。

3. 視圖創建:CFrameWnd::CreateView

CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID = AFX_IDW_PANE_FIRST)
  • 利用 pContext->m_pNewViewClass 動態創建視圖對象(CRuntimeClass::CreateObject)。
  • 調用視圖的 Create 創建子窗口(ID = AFX_IDW_PANE_FIRST,父窗口 = 框架窗口)。
  • 視圖窗口 WM_CREATE 由 CView::OnCreate 處理(通常無特殊邏輯)。

二、 框架窗口初始化與顯示:InitialUpdateFrame 全解析

void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)

調用時機:文檔模板 OpenDocumentFile 結束前,傳入新建文檔指針與 TRUE。

核心步驟(圖 5-14 流程)

  1. 設置活動視圖:若無活動視圖,查找 ID=AFX_IDW_PANE_FIRST 的視圖,調用 SetActiveView(pView, FALSE) 設置(不通知激活)。
  2. 發送 WM_INITIALUPDATE:若 bMakeVisible==TRUE,向**所有**子窗口(視圖、工具欄、狀態欄)發送 WM_INITIALUPDATE。
    • 視圖響應 CView::OnInitialUpdate → 默認調用 OnUpdate(NULL, 0, NULL) → 使客戶區無效,觸發首次 WM_PAINT 繪製。
  3. 活動視圖失活通知:調用 pView->OnActivateFrame(WA_INACTIVE, this) 保存焦點狀態(CFormView 用於恢復輸入焦點)。
  4. 激活框架窗口:調用 ActivateFrame → 觸發 WM_ACTIVATE → OnActivateTopLevel/OnActivate → 若有活動視圖調用 OnActivateView(TRUE)。
  5. 更新窗口標題與計數:若 pDoc 非空,更新 m_nWindow 計數(MDI 多視圖同一文檔編號用),設置標題(如 "Doc:1"、"Doc:2",SDI 單視圖 m_nWindow=-1 不顯示編號)。

關鍵輔助函數圖解

  • SetActiveView:失活舊視圖 (OnActivateView(FALSE)) → 更新 m_pViewActive → 通知新視圖 (OnActivateView(TRUE))。
  • ActivateFrame:ShowWindow + BringWindowToTop + SetForegroundWindow 組合,可覆蓋自定義激活邏輯(如最小化啟動)。

三、 視圖初始化:OnInitialUpdate 與 OnUpdate

  • CView::OnInitialUpdate():虛擬函數,默認調用 OnUpdate(NULL, 0, NULL)。重寫點:在此初始化滾動範圍、設置縮放比例、綁定數據源等。
  • CView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint):文檔調用 UpdateAllViews 觸發。默認使整個客戶區無效。參數用於增量更新(lHint 為提示碼,pHint 為提示對象)。

四、 WM_ACTIVATE 激活處理鏈

  1. AfxWndProc → _AfxHandleActivate:若為頂層非子窗口且頂級父窗口異,發送 WM_ACTIVATETOPLEVEL。
  2. CWnd::OnActivateTopLevel:失活時取消 Tooltip。
  3. CFrameWnd::OnActivateTopLevel:若為線程主窗口,失活活動視圖 (OnActivateView(FALSE))。
  4. CWnd::OnActivate / CFrameWnd::OnActivate:基類默認處理;框架窗口激活時重新激活活動視圖 (OnActivateView(TRUE)) 並通知幀狀態變化 (OnActivateFrame)。

五、 SDI 啟動流程回顧與 MDI 差異預覽

SDI 核心鏈:
InitInstance → 文檔模板 → OpenDocumentFile → 文檔創建 (OnNewDocument/OnOpenDocument) → 框架創建 (LoadFrame) → 視圖創建 (CreateView) → 初始化 (InitialUpdateFrame) → 激活顯示。

MDI 關鍵差異(下節詳解):

  • 主框架窗口類派生自 CMDIFrameWnd,創建於 InitInstance 早期(非延遲到打開文檔)。
  • 文檔框架窗口為 CMDIChildWnd(子窗口),由 MDI Client 窗口 (WM_MDICREATE) 管理。
  • 多文檔模板 (CMultiDocTemplate) 管理多文檔列表,無唯一文檔指針。
  • 菜單/工具欄隨活動子窗口動態切換 (WM_MDIREFRESHMENU)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved