|
ドキュメント・ビューの基本
MFCを使ってWindowsアプリケーションを作成する場合、アプリケーションウィザードでは次の3種類のスケルトンを作成することができます。
・ダイアログベース
・シングルドキュメント
・マルチドキュメント
ダイアログベースアプリは、基本的には1つのダイアログリソースを元に作成します。ダイアログにボタンやエディットボックスなどのコントロールを配置して、イベントハンドラなどを使って機能を実装していきます。簡単なアプリであればこれで十分作れます。
これに対して、シングルドキュメントインターフェース(SDI)とマルチドキュメントインターフェース(MDI)は、いわゆるウィンドウがベースのアプリを作るのに適しています。例としてはテキストエディタなどですね。ファイルを開いたり新規作成したりすると、子ウィンドウが開いて、その中で文書を表示したり編集したりします。子ウィンドウ1つが1つの文書に対応しているわけです。この子ウィンドウが1つのみのものがSDI、複数の子ウィンドウを同時に開けるものがMDIです。
SDI、MDIはダイアログベースのアプリに比べると、かなり特殊な構造を持っています。それがドキュメント・ビュー・アーキテクチャというものです。なにやら難しそうですが、基本的な考え方としては、文書(ドキュメント)と見た目(ビュー)を切り離して、別々のクラスで管理しようというものです。こうすることによって、ドキュメントクラスはデータの管理を、ビュークラスは表示部分の処理に専念できるので、プログラム構造がすっきりするわけです。
ドキュメントとビューの関係ではもう一つ特徴的なことがあります。それは1つのドキュメントに対して、ビューは複数存在することがあるということです。例えば、ある数値データがあるとします。これがドキュメントです。このデータを表示する場合、1つのウィンドウでは生データでそのまま表示して、別のウィンドウではグラフ化して表示するとします。こうすると、1つのドキュメントに対してビューは2つ存在することになります。データ自体は1つでも、その表現方法はいくつもあるということですね。
逆に1つのビューに対してドキュメントは1つだけです。ドキュメントとビューは1対多の関係になっているわけです。とは言っても単純な構造のアプリであればドキュメントとビューは1対1になることが多いです。
では、もう少し具体的な構造の話に移っていきましょう。ドキュメント・ビュー・アーキテクチャでは、
・ドキュメント
・ビュー
・フレームウィンドウ
の3つのクラスが1セットになっています。ドキュメントはCDocumentクラスの派生クラス、ビューはCViewクラスの派生クラスからの派生クラス、もしくはCViewクラスからの直接の派生クラスになります。CViewはCWndの派生クラスです。つまりビューはウィンドウです。
もう1つのフレームウィンドウというのは、CFrameWndクラスの派生クラスになります。CFrameWndもCWndの派生クラスなので、これもウィンドウです。これは何かというと、子ウィンドウの外枠の部分になります。実はビューというのはフレームウィンドウのクライアント領域全体に位置しているウィンドウで、ウィンドウの外枠や最大化、最小化ボタンなどはフレームウィンドウのものです。フレームウィンドウとビューで2重構造になっているわけですね。少し上で複数ビューについて触れましたが、例えばウィンドウを分割して複数のビューを表示する場合は、1つのフレームウィンドウ上に複数のビューが分割されて配置されることになるわけです。
さて、ビューはCViewクラスを派生させて作るわけですが、CViewクラスはビューの基本機能を持っているだけです。これを派生させて表示してみると、中身が何もない真っ白なウィンドウが表示されます。GDIを使って自分ですべての描画処理を記述したい場合はこれでもいいですが、MFCにはあらかじめいろいろなCViewの派生クラスが用意されています。クラス名だけ列挙すると、CCtrlView、CEditView、CRichEditView、CListView、CTreeView、CScrollView、CFormView、CHtmlView、CRecordView、CDaoRecordView、COleDBRecordViewといったものです。目的にあうものがあればそこから派生させたほうがいいでしょう。特にダイアログのようにウィンドウの中にコントロールを配置したい場合は、CFormViewクラスを使います。これらの1つ1つの詳細については、また別の章で解説したいと思います。
そして、この3つのクラスを結びつけるものが「ドキュメントテンプレート」というクラスです。SDIの場合はCSingleDocTemplate、MDIの場合はCMultiDocTemplateというクラスを使います。これは最初に登録するだけで、さらにその登録部分はウィザードが作ってくれるので、このクラスについてはとりあえず忘れていても問題ないでしょう。実際に自分でコードを書いていくのは、上に挙げた3つのクラス(の派生クラス)です。
では、実際にSDIベースでプロジェクトを作成してみましょう。アプリケーションウィザードで「アプリケーションの種類」に「シングルドキュメント」を指定します。

では、出来上がったプロジェクトのクラス構成を確認しておきましょう。今回はSdiという名前でプロジェクトを作成しました。クラスビューを見ると、
・CAboutDlg(CDialogの派生クラス)
・CMainFrame(CFrameWndの派生クラス)
・CSdiApp(CWinAppの派生クラス)
・CSdiDoc(CDocumentの派生クラス)
・CSdiView(CViewの派生クラス)
の5つが作成されています。CAboutDlgとCWinAppの派生クラスはダイアログベースアプリでもおなじみのものですね。SDIだとそのほかに上で述べたドキュメント、ビュー、フレームウィンドウの3つのクラスが追加されているのがわかります。

では、そのままビルドして実行してみましょう。
真っ白なウィンドウが表示されました。何もないように見えますが、ちゃんと作成されたフレームウィンドウとビューが表示されています。ステータスバーやツールバー、メニューなども最初から用意されています。これがSDIアプリの原型です。

それでは、CSdiAppクラスのInitInstance()関数を見てみましょう。不要なコメント部分は削除しています。
BOOL CSdiApp::InitInstance()
{
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
SetRegistryKey(_T("アプリケーション ウィザードで生成されたローカル アプリケーション"));
LoadStdProfileSettings(4);
// アプリケーション用のドキュメント テンプレートを登録します。ドキュメント テンプレート
// はドキュメント、フレーム ウィンドウとビューを結合するために機能します。
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSdiDoc),
RUNTIME_CLASS(CMainFrame), // メイン SDI フレーム ウィンドウ
RUNTIME_CLASS(CSdiView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
|
ここでCSingleDocTemplateクラスのオブジェクトを作成しています。CSingleDocTemplateのコンストラクタでCSdiDoc、CMainFrame、CSdiViewの3つのクラスを結び付けているのがわかりますね。そしてWinApp::AddDocTemplate()関数でドキュメントテンプレートを登録しているのがわかります。
|