文 檔/ 視 結 構
隨 著MFC2.0 的 問 世, 一 種 應 用 程 序 結 構 的 新 方 式--MFC 文 檔/ 視 結 構 出 現 了。 在 這 種 結 構 中,CFrameWnd 繁 重 的 任 務 被 委 派 給 幾 個 不 同 類, 實 現 了 數 據 存 儲 和 顯 示 的 分 離。 一 般 情 況 下, 采 用 文 檔/ 視 結 構 的 應 用 程 序 至 少 應 由 以 下 對 象 組 成: 應 用 程 序 是 一 個CwinApp 派 生 對 象, 它 充 當 全 部 應 用 程 序 的 容 器。 應 用 程 序 沿 消 息 映 射 網 絡 分 配 消 息 給 它 的 所 有 子 程 序。 框 架 窗 口 是 一CfrmeWnd 派 生 對 象。 文 檔 是 一 個CDocument 派 生 對 象, 它 存 儲 應 用 程 序 的 數 據, 并 把 這 些 信 息 提 供 給 應 用 程 序 的 其 余 部 分。 視 窗 是Cview 派 生 對 象, 它 與 其 父 框 架 窗 口 用 戶 區 對 齊。 視 窗 接 受 用 戶 對 應 用 程 序 的 輸 入 并 顯 示 相 關 聯 的 文 檔 數 據。
MFC 調 用 命 令 處 理 程 序 以 響 應 發 生 在 應 用 程 序 中 的 事 件。 命 令 發 送 的 優 先 級 是:
活 動 的 視 圖 框 架 窗 口 → 文 檔 → 應 用 程 序 → 默 認 窗 口 過 程(DefWindowsProc)
與 文 檔/ 視 結 構 有 關 的在 文 檔/ 視 應 用 程 序 中,CWinApp 對 象 擁 有 并 控 制 文 檔 模 板, 后 者 產 生 文 檔、 框 架 窗 口 及 視 窗。 這 種 相 互 關 系 如 圖1 所 示:
圖1 應 程 序、 文 檔 模 板、 文 檔、 框 架 窗 口
及 視 窗 對 象 間 的 關 系
在MDI 應 用 程 序 中, 可 以 處 理 多 個 文 檔 類 型, 即 多 個 文 檔 模 板, 每 個 模 板 又 可 以 有 多 個 文 檔, 每 個 文 檔 又 可 以 多 視 顯 示。 為 管 理 方 便, 上 一 級 往 往 保 留 了 下 一 級 的 指 針 列 表, 如 圖2 所 示:
圖2 MDI 中 的 指 針 列 表
圖3 存 取 關 系( 箭 頭 表 示 獲 得 關 系)
下 面 一 段 代 碼, 就 是 利 用CDocTemplate、CDocument 和CView 之 間 的 存 取 關 系, 遍 歷 整 個 文 檔 模 板、 文 檔 以 及 視。
CMyApp * pMyApp = (CMyApp *)AfxGetApp(); POSITION p = pMyApp ->GetFirstDocTemplatePosition(); while(p!= NULL) { CDocTemplate * pDocTemplate = pMyApp →GetNextDocTemplate(p); POSITION p1 = pDocTemplate ->GetFirstDocPosition(); while(p1 != NULL) { CDocument * pDocument = pDocTemplate ->GetNextDoc(p1); POSITION p2 = pDocument ->GetFirstViewPosition(); while(p2 != NULL){ CView * pView = pDocument ->GetNextView(p2); } } }CwinApp::OnFileNew、CwinApp::
1. CwinApp::OnFileNew 和CwinApp::OnFileOpen 函 數 的 簡 單 流 程。
圖4 File New/Open 流 程 圖
核 心 操 作 是CDocTemplate::OpenDocument 函 數。 其 函 數 原 型 為:
virtual CDocument * CDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE ) = 0;
2. Window/New 命 令 的 程 序 流 程。
當 主 框 架 窗 口 上 有 子 窗 口 時, 選 擇Window/New 命 令 可 以 生 成 該 活 動 子 窗 口 的 影 像。 它 們 有 相 同 的 文 檔 模 板、 相 同 的 文 檔。 其 流 程 如 下:
1. 如 何 根 據 自 己 的 要 求 來 選 擇 文 檔 模 板 及 相 應 的 視 和 文 檔。
如 果 應 用 程 序 需 要 處 理 多 種 類 型 的 文 檔, 并 且 何 時 打 開 何 種 文 檔 均 需 程 序 員 手 工 控 制, 程 序 員 必 須 對 文 檔 模 板 進 行 編 程。
例 如, 需 要 處 理AVI 和BMP 兩 種 文 件 類 型。AVI 和BMP 的 數 據 存 放 格 式 不 同, 不 能 用 同 一 的 數 據 結 構 來 描 述, 同 時, 由 于AVI 是 圖 像 序 列,BMP 僅 是 一 幅 圖 像, 它 們 的 顯 示 是 肯 定 不 一 樣 的, 基 于 此, 筆 者 分 別 建 立 兩 套 文 檔 模 板, 兩 套 框 架 窗 口, 兩 套 文 檔 和 兩 套 視, 分 別 用 于AVI 和BMP 的 數 據 存 放 和 顯 示。 具 體 步 驟 如 下:
?。⊿tep 1): 在 應 用 程 序 類(CWinApp) 的 派 生 類 中 增 加 文 檔 模 板 成 員 變 量。
class C3dlcsApp : public CWinApp { public: CMultiDocTemplate * m_pAVIDocTemplate; CMultiDocTemplate * m_pBMPDocTemplate; } (Step 2): 在 主 框 架 中 增 加 菜 單 響 應: void CMainFrame::OnFileOpen() { CFileDialog my(true); if(my.DoModal()==IDOK) { CString FileName = my.GetPathName(); CString FileExt = my.GetFileExt(); if((FileExt=="AVI")||(FileExt=="avi")){ CString FileName=my.GetPathName(); CMultiDocTemplate *pAVIDocTemplate=pMyApp →m_pAVIDocTemplate; pAVIDocTemplate →OpenDocumentFile(FileName) } else if((FileExt == "BMP") || (FileExt == "bmp")) { CMyApp * p3dlcsApp = (CMyApp *)AfxGetApp(); CMultiDocTemplate *pDATDocTemplate=pMyApp →m_pBMPDocTemplate; pDATDocTemplate ->OpenDocumentFile(FileName); } else{ AfxMessageBox("Yor select a file not supported!");retum } } }2. 切 分 窗 口 與 文 檔/ 視 結 構。
一 個 文 檔 可 以 有 多 個 視, 切 分 窗 口 即 是 表 示 多 視 的 一 種 方 法。 切 分 窗 口 是 通 過 類CSplitterWnd 來 表 示 的, 對Window 來 說,CSplitterWnd 對 象 是 一 個 真 正 的 窗 口, 它 完 全 占 據 了 框 架 窗 口 的 客 戶 區 域, 而 視 窗 口 則 占 據 了 切 分 窗 口 的 窗 片 區 域。 切 分 窗 口 并 不 參 與 命 令 傳 遞 機 制,( 窗 片 中) 活 動 的 視 窗 從 邏 輯 上 來 看 直 接 被 連 到 了 它 的 框 架 窗 口 中。
切 分 窗 口 可 以 分 為 動 態 和 靜 態 兩 種。 前 者 較 簡 單, 本 文 僅 討 論 后 者。 創 建 切 分 窗 口 的 步 驟 如 下:
?。⊿tep 1): 在 自 己 的 框 架 窗 口 中 聲 明 成 員 變 量。
class CMyFrame : public CMDIChildWnd { CSplitterWnd m_Splitter; CSplitterWnd m_Splitter2; } (Step 2): 重 載CMDIChildWnd::OnCreateClient 函 數, 創 建 切 分 窗 口。 BOOL CMyFrame::OnCreateClient (LPCREATESTRUCT lpcs, CCreateContext * pContext) { BOOL btn = m_Splitter.CreateStatic(this,1,2); btn |= m_Splitter.CreateView(0,0, RUNTIME_CLASS(CAVIDispView), m_Splitter2.CreateStatic( &m_Splitter,2,1, WS_CHILD|WS_VISIBLE|WS_BORDER, m_Splitter.IdFromRowCol(0,1)) btn |= m_Splitter2.CreateView (0, 0, RUNTIME_CLASS(CBMPView),CSize(100,100),pContext); btn |= m_Splitter2.CreateView (1, 0, RUNTIME_CLASS(CAVIView), CSize(100,100),pContext); return btn; }CFrameWnd::OnCreateClient 函 數 原 形 為:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CcreateContext * pContext);
缺 省 的CMDIChildWnd::OnCreateClient 函 數 根 據pContext 參 數 提 供 的 信 息, 調 用CFrameWnd::CreateView 函 數 創 建 一 個 視。 可 以 重 載 該 函 數, 加 載CCreateContext 對 象 中 傳 遞 的 值, 或 改 變 框 架 窗 口 主 客 戶 區 中 控 制 的 創 建 方 式。