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

MFC 指針獲取完全手冊:從 App、主框架、文檔、視圖到工具欄、狀態欄、分割視圖的萬能導航圖

     編輯:關於C語言

MFC 文檔/視圖架構中,物件之間透過指針網絡關聯。熟練掌握「從任何一點導航到任意目標」是 MFC 開發效率的分水嶺。本文系統整理 15 類核心指針獲取模式,涵蓋單文檔/多文檔 (SDI/MDI)、分割視圖、運行時類型識別 (RTTI)、文檔模板枚舉,附帶正反例代碼與通用導航口訣。

一、核心入口點:三大全局獲取函數

函數返回類型用途
AfxGetApp()`CWinApp*`應用程式物件單例
AfxGetMainWnd()`CWnd*`主框架視窗 (`CFrameWnd*`/`CMDIFrameWnd*`)
AfxGetInstanceHandle()`HINSTANCE`模組實例句柄 (資源載入用)

二、主框架與應用層導航


// 1. App → MainFrame
CMainFrame* pMain = (CMainFrame*)AfxGetApp()->m_pMainWnd; // 推薦
// 或
CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();         // 等價

// 2. MainFrame → Menu
CMenu* pMenu = pMain->GetMenu(); // 或 AfxGetMainWnd()->GetMenu()

// 3. MainFrame → ToolBar / StatusBar (成員變量法,需預先在 MainFrame 宣告)
CToolBar* pTB = &pMain->m_wndToolBar;
CStatusBar* pSB = &pMain->m_wndStatusBar;

// 4. 通用子視窗查找法 (無需成員變量)
CToolBar* pTB = (CToolBar*)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);
CStatusBar* pSB = (CStatusBar*)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);

三、文檔/視圖導航:SDI vs MDI 關鍵差異

SDI (單文檔介面)


CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
CMyDoc* pDoc = (CMyDoc*)pMain->GetActiveDocument(); // 唯一文檔
CMyView* pView = (CMyView*)pMain->GetActiveView();  // 唯一視圖

MDI (多文檔介面)


CMDIFrameWnd* pMain = (CMDIFrameWnd*)AfxGetMainWnd();
CMDIChildWnd* pChild = (CMDIChildWnd*)pMain->MDIGetActive(); // 或 GetActiveFrame()
CMyDoc* pDoc = (CMyDoc*)pChild->GetActiveDocument();
CMyView* pView = (CMyView*)pChild->GetActiveView();

四、視圖 ↔ 文檔 雙向導航


// View → Doc (視圖類成員函數)
CMyDoc* pDoc = GetDocument(); // 自動生成,含 ASSERT 檢查

// Doc → View (枚舉所有視圖)
POSITION pos = GetFirstViewPosition();
while (pos) {
    CView* pView = GetNextView(pos);
    if (pView->IsKindOf(RUNTIME_CLASS(CMyView))) {
        // 找到目標視圖
        break;
    }
}

// 通用輔助函數 (加入 Doc 類)
CView* CMyDoc::GetView(CRuntimeClass* pClass) {
    POSITION pos = GetFirstViewPosition();
    CView* pView = NULL;
    while (pos) {
        pView = GetNextView(pos);
        if (pView->IsKindOf(pClass)) break;
    }
    return (pView && pView->IsKindOf(pClass)) ? pView : NULL;
}

// 使用
CMyView* pView = (CMyView*)GetView(RUNTIME_CLASS(CMyView));

五、視圖 ↔ 視圖:以文檔為中轉


// 在 CMyViewA 獲取 CMyViewB
CMyDoc* pDoc = GetDocument();
CMyViewB* pViewB = (CMyViewB*)pDoc->GetView(RUNTIME_CLASS(CMyViewB));

六、分割視圖 (`CSplitterWnd`) 面板存取


// MainFrame 成員
CSplitterWnd m_wndSplitter;

// OnCreateClient 創建
m_wndSplitter.CreateStatic(this, 2, 1); // 2行1列
m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CView1), CSize(100,100), pContext);
m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CView2), CSize(100,100), pContext);

// 獲取面板指針
CView1* pView1 = (CView1*)m_wndSplitter.GetPane(0, 0);
CView2* pView2 = (CView2*)m_wndSplitter.GetPane(1, 0);

七、控件指針獲取


// 1. 對話框/視圖內控件 (DDX 綁定首選,次選 GetDlgItem)
CButton* pBtn = (CButton*)GetDlgItem(IDC_MYBUTTON); // 需包含 afxwin.h

// 2. ClassWizard 綁定成員變量 (最推薦)
// 在 ClassWizard → Member Variables → Add Variable → Control

八、文檔模板與文檔枚舉 (MDI/多模板場景)


// App 遍歷所有文檔模板
POSITION tplPos = AfxGetApp()->GetFirstDocTemplatePosition();
while (tplPos) {
    CDocTemplate* pTpl = AfxGetApp()->GetNextDocTemplate(tplPos);
    // 判斷模板類型
    CString str; pTpl->GetDocString(str, CDocTemplate::docName);
    
    // 模板遍歷其文檔
    POSITION docPos = pTpl->GetFirstDocPosition();
    while (docPos) {
        CDocument* pDoc = pTpl->GetNextDoc(docPos);
        // 判斷文檔
        if (pDoc->GetTitle() == "Target") { /* ... */ }
    }
}

// Doc → 所屬模板
CDocTemplate* pTpl = pDoc->GetDocTemplate();

九、滑鼠座標獲取子視窗


CWnd* pChild = pParent->ChildWindowFromPoint(pt); // 單一參數
// 或帶旗標
CWnd* pChild = pParent->ChildWindowFromPoint(pt, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);

// 旗標含義
CWP_ALL           // 不忽略任何
CWP_SKIPINVISIBLE // 忽略不可見
CWP_SKIPDISABLED  // 忽略禁用
CWP_SKIPTRANSPARENT // 忽略透明 (WS_EX_TRANSPARENT)

// ⚠️ 返回偽指針,不可長期保存,僅即時使用

十、萬能導航口訣 (13 步走遍 MFC 物件圖)

  1. `AfxGetApp()` → `CWinApp*`
  2. `AfxGetMainWnd()` → 主框架
  3. `CMDIFrameWnd::GetActiveFrame()` → MDI 子框架
  4. `GetNextWindow()` 遍歷子視窗 (配合成員標識)
  5. `CWinApp::GetFirstDocTemplatePosition()` + `GetNextDocTemplate()` 遍歷模板
  6. `CDocTemplate::GetDocString()` 識別模板
  7. `CDocTemplate::GetFirstDocPosition()` + `GetNextDoc()` 遍歷文檔
  8. `CDocument::GetDocTemplate()` 反查模板
  9. `CDocument::GetTitle()`/`GetPathName()` 識別文檔
  10. `CDocument::GetFirstViewPosition()` + `GetNextView()` 遍歷視圖
  11. `CView::GetDocument()` → 文檔
  12. `CFrameWnd::GetActiveView()` → 視圖
  13. `CFrameWnd::GetActiveDocument()` → 文檔
  14. `CView::GetParentFrame()` → 框架

十一、常見錯誤與避坑

錯誤代碼問題修正
`CView* p = GetActiveView();`在 Doc/非 Frame 類中調用僅 `CFrameWnd` 系有此函數,Doc 用 `GetFirstViewPosition()`
`CMainFrame* p = (CMainFrame*)GetParent();`視圖父視窗不一定是 MainFrame (MDI 為 ChildFrame)用 `GetParentFrame()` 獲取直接框架父視窗
保存 `ChildWindowFromPoint` 返回指針偽指針,臨時對象即時使用,不保存
直接 `static_cast(GetActiveView())`無 RTTI 檢查,類型不匹配導致崩潰用 `DYNAMIC_DOWNCAST(CMyView, GetActiveView())` 或 `IsKindOf`

將這張導航圖貼在工位旁,下次需要「從這裡拿到那個指針」時,按圖索驥,秒級定位,拒絕盲目試錯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved