MFC ドキュメントとビューの分離
SDIアプリケーション
MFCアプリケーションの開始
以下の順序でMFCアプリケーションは開始される
- グローバルオブジェクト theApp(CWinAppの派生クラス AppWizardが作成)を生成
- MFCライブラリの一部であるグローバル関数 WinMain(エントリポイント)を呼び出す
- WinMainは、CWinAppから派生されているクラスの唯一のインスタンスを探す
- WinMainは、theAppのInitInstanceメンバ関数を呼び出す
- 派生クラスでオーバーライドされたInitInstance関数は、ドキュメントのロードと、メイン フレーム ウィンドウ および ビュー ウィンドウの表示処理を開始
- WinMainはtheAppのRunメンバ関数を呼び出す
- Runメンバ関数は、ウィンドウメッセージとコマンドメッセージのディスパッチ処理を開始
ドキュメントテンプレート
- InitInstance関数に、以下のようなコードが含まれている
BOOL CSdiSampleApp::InitInstance()
{
:
// アプリケーション用のドキュメント テンプレートを登録します。ドキュメント テンプレート
// はドキュメント、フレーム ウィンドウとビューを結合するために機能します。
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSdiSampleDoc),
RUNTIME_CLASS(CMainFrame), // メイン SDI フレーム ウィンドウ
RUNTIME_CLASS(CSdiSampleView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
クラス
|
内容
|
ドキュメント クラス
|
CDocument クラスから派生
|
ビュー クラス
|
ドキュメント クラスのデータを表示します。このクラスは、CView、CScrollView、CFormView、または CEditView から派生
|
フレーム ウィンドウ クラス
|
ビューを保持。SDI のドキュメント テンプレートは、CFrameWnd から派生。メイン フレーム ウィンドウの動作をカスタマイズする必要がない場合、派生クラスを作らずに直接 CFrameWnd を使用できます
|
空のドキュメントを生成 CWinApp::OnFileNew関数
InitInstance関数は、AddDocTemplateメンバ関数を呼び出した後、OnFileNewを呼び出し(CWinApp::ProcessShellCommandを介して)次のことを行う。
処理内容
|
備考
|
1.ドキュメントオブジェクトを生成
|
ディスクからのデータ読み出しは行わない
|
2.CMainFrameメインフレームオブジェクトを生成
|
メインフレームウィンドウも生成するが、表示は行わない。メインフレームウィンドウはIDR_MAINFRAMEメニュー、ツールバー、ステータスバーを含む
|
3.ビューオブジェクトを生成
|
ビューウィンドウも生成するが表示は行わない
|
4.ドキュメント、メインフレーム、ビューの各オブジェクト間の接続
|
AddDocTemplate関数によるクラスの接続と混同しない
|
5.ドキュメントオブジェクトのCDocument::OnNewDocument仮想メンバ関数を呼び出す
|
DeleteContents仮想関数が呼び出される
|
6.ビューオブジェクトのCView::OnInitialUpdate仮想メンバ関数を呼び出す
|
|
7.フレームオブジェクトのCFrameWnd::ActivateFrame仮想関数を呼び出す
|
メニュー、ビューウィンドウ、コントロールバーを含むメインフレームウィンドウを表示する
|
- CDocument::OnNewDocumentやCView::OnInitialなどの関数は初期化の作業を行うのに最適
ファイルを開く OnFileOpen関数
AppWizardは、アプリケーション生成時に、「ファイル-開く」メニューをCWinApp::OnFileOpenメンバ関数にマップする。この関数が呼び出されると、以下の処理を行う。
処理内容
|
備考
|
ユーザにファイルの選択を要求
|
CWinApp の DoPromptFileName メンバ関数は、標準の FileOpen ダイアログを呼び出し、現在のドキュメント テンプレートから得たファイル拡張子を表示
|
既に存在しているドキュメントオブジェクトのCDocument::OnOpenDocument仮想関数を呼び出す
|
この関数はファイルを開き、CDocument::DeleteContentsを呼び出し、CArchiveオブジェクトを生成しロード状態に設定。次にSerialize関数を呼び出し、データをロード
|
ビューのOnInitialUpdate関数を呼び出す
|
- 現在のドキュメントの内容を消去するのに適した方法は、CDocument::DeleteContents仮想関数をオーバーライドする。
- CDocument::DeleteContents関数は、OnNewDocument関数や、OnOpenDocument関数、ドキュメントを閉じる場合も呼び出される。
- デストラクタは、オブジェクトの終了時まで存続するアイテムの後始末に利用する
ファイルの上書き保存、名前をつけて保存 CDocument::OnFileSave
- AppWizardは、「ファイル-上書き保存」メニューを、CDocument::OnFileSaveメンバ関数にマップする
処理内容
|
備考
|
CDocument::OnFileSaveメンバ関数の呼び出し。上書き保存の場合、OnFileSaveAs関数
|
CDocument::OnSaveDocument関数の呼び出
|
OnFileSaveにより呼び出される
|
CDocument::Siliarize関数を呼び出す
|
- CDocumentのm_bModified データメンバはドキュメントが変更されている場合TRUEとなる
- ドキュメントが変更された場合SetModifiedFlag関数を使ってフラグをTRUEに設定する
MDIアプリケーション
MFCアプリケーションの開始
- 実行開始のシーケンスは、SDIアプリケーションとほとんど同じ。
- MDIのInitInstance関数は、AddDocTemplate関数の呼び出し以降がSDIと若干ことなる。
MDIドキュメントテンプレートクラス
BOOL CMdiSampleApp::InitInstance()
{
:
// アプリケーション用のドキュメント テンプレートを登録します。ドキュメント テンプレート
// はドキュメント、フレーム ウィンドウとビューを結合するために機能します。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_MdiSampleTYPE,
RUNTIME_CLASS(CMdiSampleDoc),
RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
RUNTIME_CLASS(CMdiSampleView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
- MDIアプリケーションでは、複数のドキュメントタイプを使うことができ、同時に複数のドキュメントオブジェクトを存在させることができる
基本クラス
|
AppWizard作成
|
オブジェクト数
|
メニューとコントロール
|
ビュー
|
生成
|
CMDIFrameWnd
|
CMainFrame
|
1つ
|
あり
|
なし
|
アプリケーションクラスのInitInstance
|
CMDIChildWnd
|
CCHildFrame
|
それぞれの子ウィンドウに1つずつ
|
なし
|
あり
|
新しい子ウィンドウが開かれたときに、アプリケーションフレームワークが生成
|
- MDIのフレームウィンドウとビューウィンドウの関係
空のドキュメントの作成 CWinApp::OnFileNew関数
- SDIのInitInstance関数と同様に、MDIのInitInstance関数は、ProcessShellCommand関数を通じて、OnFileNewを呼び出す。
- このときメインフレームウィンドウは既に生成されている。
OnFileNewは、CMultiDocTemplateのOpenDocumentFile関数の呼び出しを行ってから、次の手順を実行する
処理
|
備考
|
1.ドキュメントオブジェクトを生成
|
ディスクからのデータ読み込みは行わない
|
2.子フレームウィンドウオブジェクト(CChildFrame)を生成
|
子フレームウィンドウを生成するが、表示しない。IDR_MAINFRAMEメニューをIDR_[アプリ名]TYPEメニューで置き換える
|
3.ビューオブジェクトを生成
|
ビューウィンドウも生成するが表示はしない
|
4.ドキュメント、メインフレームウィンドウ、ビューの各オブジェクト間の接続を確立
|
AddDocTemplateによって確立されるクラス間の関連と混同しないこと
|
ドキュメントオブジェクト用のOnNewDocument仮想メンバ関数を呼び出す
|
ビューオブジェクトのOnInitialUpdate仮想メンバ関数を呼び出す
|
子フレームオブジェクト用のActivateFrame仮想メンバ関数を呼び出す
|
フレームウィンドウ、ビューウィンドウを表示
|
既存のドキュメントに追加のビューを作成する
メニューから、新規ウィンドウを選択すると、現在選択中のドキュメントにリンクされた新しい子ウィンドウを開く。
処理内容
|
備考
|
1.子フレームオブジェクト(CChildFrame)を生成
|
子フレームウィンドウを生成するが表示しない
|
2.ビューオブジェクトを生成
|
ビューウィンドウも生成するが表示しない
|
3.新しいビューオブジェクトと既存のドキュメントとメインフレームオブジェクト間の接続
|
4.ビューオブジェクトのOnInitialUpdate仮想メンバ関数を呼び出す
|
5.子フレームオブジェクトのActivateFrame仮想メンバ関数を呼び出し、フレームウィンドウとビューウィンドウを表示
|
ドキュメントのロードと保存
- SDIと同様ドキュメントのロードと保存を行うが、2つの重要な相違点がある
- ドキュメントファイルをディスクからロードするたびに新しいドキュメントオブジェクトが生成される
- 子ウィンドウが閉じられるとドキュメントオブジェクトも破棄される
- ロードを行う前に、ドキュメント内容の消去の心配はしなくてよいが、SDIとの互換性を維持するために、CDocument::DeleteContens関数はオーバーライドすべき
複数のドキュメントテンプレート
- MDIアプリケーションでは、AddDocTemplate関数を複数回呼び出すことで、複数のドキュメントをサポートすることができる。
- それぞれのテンプレートは異なるドキュメント、ビュー、MDI子フレームクラスの組み合わせを指定することができる