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

MFC 混合 MDI/SDI 窗體架構實作:單一文件多視圖的框架視窗設計

     編輯:關於VC++

需求背景

許多管理資訊系統 (MIS) 的主視窗都具備相似特徵:透過框架選單開啟不同類型的檢視視窗,這些視窗擁有 MDI 子視窗的最小化/最大化/還原能力,但點選選單項目只能產生單一實例 (類似 SDI 行為)。這種「單一文件多視圖」的混合架構兼具條理與彈性。本文記錄使用 VC 6.0 實作此架構的完整過程,涉及 MFC 文件/視圖架構的核心機制。

實作步驟詳解

1. 建立基礎 MDI 專案

新建 MFC AppWizard (exe) 專案,命名 mdisdi,選擇 MDI 架構,其餘採預設值。

2. 應用程式類別擴充文件模板指標

在 CApp 衍生類別 (CMdisdiApp) 的 public 區段新增兩個文件模板指標:

public:
    CMultiDocTemplate* pDoctemp1;
    CMultiDocTemplate* pDoctemp2;

3. 修改 InitInstance() 註冊第一組文件模板

將原本的區域變數 pDocTemplate 改為使用成員指標 pDoctemp1:

pDoctemp1 = new CMultiDocTemplate(
    IDR_MDISDITYPE,
    RUNTIME_CLASS(CMdisdiDoc),
    RUNTIME_CLASS(CChildFrame),
    RUNTIME_CLASS(CMdisdiView));
AddDocTemplate(pDoctemp1);

4. 新增第二組 Document/Frame/View 類別

  • 新增 CDoc2 (基類 CDocument)
  • 新增 CChildFrame2 (基類 CMDIChildWnd)
  • 新增 CView2 (基類 CFormView),在對話方塊屬性中指定 Document 為 CDoc2

5. 註冊第二組文件模板

同樣使用成員指標 pDoctemp2,並修正 Frame 類別為 CChildFrame2:

pDoctemp2 = new CMultiDocTemplate(
    IDR_VIEW2_TMPL,
    RUNTIME_CLASS(CDoc2),
    RUNTIME_CLASS(CChildFrame2),
    RUNTIME_CLASS(CView2));
AddDocTemplate(pDoctemp2);

別忘在 mdisdi.cpp 頭部加入 #include "Doc2.h"。

6. 資源編輯:建立對應選單與工具列資源

  1. 修改 IDR_MAINFRAME 選單,新增「功能」主選單,包含「視窗1」與「視窗2」兩個項目。
  2. 複製 IDR_MAINFRAME 產生 IDR_MAINFRAME1、IDR_MAINFRAME2,分別重命名為 IDR_MDISDITYPE、IDR_VIEW2_TMPL,分別對應兩組文件模板。

7. 主框架視窗類別新增選單命令處理與文件指標

在 MainFrm.h 加入標頭檔與文件指標:

#include "mdisdiDoc.h"
#include "Doc2.h"

public:
    CMdisdiDoc * pDoc1;
    CDoc2 * pDoc2;

在 MainFrm.cpp 實作選單命令處理函式,核心邏輯:若文件不存在則建立新文件;若已存在則激活現有視圖框架:

void CMainFrame::OnMenuitem32771() // 視窗1
{
    if(pDoc1 == NULL)
    {
        CMdisdiApp * pApp = (CMdisdiApp *)AfxGetApp();
        pDoc1 = (CMdisdiDoc *)pApp->pDoctemp1->OpenDocumentFile(NULL);
    }
    else
    {
        POSITION pos = pDoc1->GetFirstViewPosition();
        CView * pView = pDoc1->GetNextView(pos);
        pView->GetParentFrame()->ActivateFrame();
    }
}

void CMainFrame::OnMenuitem32772() // 視窗2
{
    if(pDoc2 == NULL)
    {
        CMdisdiApp * pApp = (CMdisdiApp *)AfxGetApp();
        pDoc2 = (CDoc2 *)pApp->pDoctemp2->OpenDocumentFile(NULL);
    }
    else
    {
        POSITION pos = pDoc2->GetFirstViewPosition();
        CView * pView = pDoc2->GetNextView(pos);
        pView->GetParentFrame()->ActivateFrame();
    }
}

8. 初始化與清理文件指標

  • CMainFrame 建構式將 pDoc1、pDoc2 初始化為 NULL。
  • CChildFrame 解構式中取得主視窗指標,將 pDoc1 歸零。
  • CChildFrame2 解構式同理將 pDoc2 歸零。
// ChildFrm.cpp
#include "MainFrm.h"
CChildFrame::~CChildFrame()
{
    CMainFrame * pMain = (CMainFrame *)AfxGetMainWnd();
    pMain->pDoc1 = NULL;
}

// ChildFrame2.cpp
#include "MainFrm.h"
CChildFrame2::~CChildFrame2()
{
    CMainFrame * pMain = (CMainFrame *)AfxGetMainWnd();
    pMain->pDoc2 = NULL;
}

9. 移除啟動時的視圖選擇對話方塊

在 InitInstance() 註解掉命令列處理碼,避免啟動時彈出「新增檔案」對話方塊:

// CCommandLineInfo cmdInfo;
// ParseCommandLine(cmdInfo);
// if (!ProcessShellCommand(cmdInfo))
//     return FALSE;

架構優勢總結

此設計讓單一 MDI 框架下管理多組獨立的 Document/View 組合,每組行為如 SDI (單一實例) 卻保有 MDI 子視窗的視覺操作體驗。透過主框架持有文件指標並攔截子視窗銷毀事件,精確控制實例生命週期,是 MFC 文件/視圖架構進階應用的經典範例。

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