SDIアプリケーションの基本


■ SDIプロジェクトの作成
今回は、SDIアプリケーションを作成してみましょう。プロジェクト名は"sditest"にします。
SDIとは、シングル・ドキュメント・インターフェースの略で、単一のViewを持つアプリケーションを意味します。具体的には、Windowsに付属するノートパッド、インターネットエクスプローラがSDIアプリケーションです。
作成方法は、ダイアログの編集と同様です。MFC AppWizardのステップ1の[作成するアプリケーションの種類]で[SDI]を選択します。ダイアログの時と同様に、今回のその他の項目はデフォルトのままで行うので、この時点で[終了]ボタンを押しウィザードを完了させます。
この時点で、以下の5つのクラスが自動的に生成されます。
CAboutDlg ...... ヘルプのバージョン情報表示のためのダイアログ。
CMainFrame ..... ウィンドのフレーム(枠)に関する処理を管理する。メニュー、ツールバー、ステータスバーそしてビューとドキュメントの管理を行う。
CSditestApp ..... ウィンドウのメイン処理を行う。初期化や終了処理など。
CSditestDoc ..... ドキュメントの管理を行う。ファイル管理など。
CSditestView ..... 通常ドキュメントを文字やグラフィックとして表示するためのウィンドウ。

今回は、デフォルトの設定のままなので、CSditestViewはビューの基本クラスであるCViewになっています。
CViewは、いわば白紙のパレットで文字やグラフィックを表示できますが全て手操作で行わなければなりません。
■ とりあえず実行してみましょう
ダイアログの時と同様に、まずは何も手を加えずにビルドして実行してみましょう。
今回は、いきなり[ビルド]メニューの[デバッグの開始]の[実行](F5)を、選択して見ましょう。すると、ビルドを実行するかどうかのダイアログが表示されるので、[はい]を選択して下さい。ビルドが実行されSditestのウィンドウが表示されます。

ここでお分かりのように、この時点で既に幾つかのデフォルトのメニュー、ツールバーのボタンそしてステータスバーが作られていますね。
ウィンドウ内でピクセル座標を扱う場合はウィンドウのクライアント座標系を用いることになります。ウィンドウ内の赤字で示されるように、左上が原点となり右方向はX+方向、下方向はY+方向になります。
通常数学で使うグラフとはY方向が逆になることを覚えておいてください。
■ ビュー上に文字を表示してみましょう
真っ白なウィンドウだと少しさびしいので、お決まりの文字を表示してみましょう。
ビュー上に描画や文字表示を行う場合は、全てOnDraw関数内で行います。この関数がウィンドウズの独特の処理の内の一つと言えるでしょう。というのは、ウィンドウは他のウィンドウに隠されたり、またウィンドウのサイズを変更することがあります。この関数はそういったときにシステムが自動的にこの関数を呼び出しビューの更新を行います。もちろん初期化時、それとプログラムでシステム関数を使い呼び出すこともできます。
実際にコードを見てみましょう。
void CSditestView::OnDraw(CDC* pDC)
{
        CSditestDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: この場所にネイティブ データ用の描画コードを追加します。
}
ここでは、ドキュメントのポインタを取り出している他には、デフォルトの処理は何もありません。TODO:が示しているようにここから先に描画コードを追加していきます。
その前に、OnDrawの引数にCDCのポインタであるpDCがありますね。このCDCは、デバイスコンテキスト オブジェクトと呼ばれるものでウィンドウズの描画、テキスト表示関数、ビットマップ関係の関数等がカプセル化されたクラスです。描画のためのユーティリティーの関数と考えて良いと思います。そしてこのビューに割り当てられたCDCクラスは、このビューの表示エリアを管理しています。
では、文字を表示しましょう。文字列はお決まりの"Hellow world"で、青で表示します。ここで表示位置ですが、ウィンドウのサイズが変更されても常に上下中央に表示するようにしてみましょう。以下が追加後のOnDraw関数です。
void CSditestView::OnDraw(CDC* pDC)
{
        CSditestDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: この場所にネイティブ データ用の描画コードを追加します。
        COLORREF                colText         = RGB( 0, 0, 255);      // テキスト色: 青色.
        pDC->SetTextColor( colText);                    // テキスト色指定.
        CRect           rect;
        GetClientRect( &rect);                                  // 表示エリアのサイズを取得する.
        // テキスト出力.
        pDC->DrawText( "Hellow world", rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
関数GetClientRectは前項で説明したクライアント座標系におけるウィンドウのサイズを取得するためのものです。
DrawTextは文字列を決められた枠内に表示する関数です。詳細はヘルプを見てください。
(ヘルプの便利な開き方としては、ソースエディタ上で知りたい関数名の上にカーソルを移動してF1キーを押すとヘルプでその頁を自動的に捜してくれます。)
この例では、テキスト表示のみですが、ヘルプでCDCのクラスメンバを見ると、他にもさまざまな関数があります。
線や円を書いたり、ビットマップを表示したりすることができます。興味がある人はトライしてみてください。
■メニューを追加してダイアログを表示する
まず新しいダイアログを一つ追加してみましょう。やり方は、これまでに説明したのとまったく同じです。
この例では、ダイアログのIDは、IDD_SUBDLGにします。
次に、このダイアログのクラスを作成します。クラス名はCSubDlg、ファイル名はSubDlg.cppとSubDlg.hです。
ここまでは、前章とまったく同じです。

では、メニューを追加しましょう。次の手順に従って作成します。
@メニューを開く
ResourceView上でメニューの項目の下にあるIDR_MAINFRAMEをダブルクリックして開きます。
これは、SDIを作成した場合、自動的に作成されるデフォルトのメニューです。これを自由に編集して使うことができます。
ファイル、編集、編集、ヘルプの4つが元から存在しています。これらの何れかの下に新しいメニュー項目を追加することができます。あるいは新しいプルダウンメニューやプルダウンメニューを持たないメニュー項目も追加することができます。
今回の例では、編集の下にダイアログ表示というメニューを追加してみましょう。
まず、編集をクリックすると以下ようなプルダウンメニューが表示されます。

Aメニュー項目を追加する
メニュー項目を追加する位置もどこでも良いのですが、一番下のあいているところをダブルクリックしてください。
すると以下のダイアログが表示されます。

まず、IDですがプログラム内でメニュー項目を認識するためのIDです。通常ID_で始まる文字列を使用しますが、今回はID_TESTにします。
次に、キャプションはメニューに表示される文字列です。&Dはメニューをマウスでなくキーボードで選択する際に指定するキーアサインで、この場合はALT+Dを押すことにより選択されることを示します。
プロンプトはメニューの説明で、\nにより前半と後半に分かれます。前半は、マウスがこの項目の上に来たときステータスバーに表示される文字列で、後半は次の項で説明するツールバーのこのアイコンの上にマウスが来たとき表示される文字列(ツールチップ)を表します。
他の項目はこの例ではこのままでOKです。
(ちなみにセパレータとはメニュー上のグループを分ける線を追加するときにチェックします。)
ダイアログを閉じてメニューの作成を終了します。メニューエディターも保存して閉じましょう。
B追加したメニュー項目の処理を作る
通常メニューの処理は、メインフレーム内、時にはドキュメントやビュー内で処理しますが、この例ではメインフレーム内で行うことにします。
[表示]の[ClassWizard]を選択しクラスウィザードを呼び出します。[クラス名]はCMainFrame[オブジェクト]は先ほど追加したID_TESTを指定します。次に[関数の追加]ボタンを押すと関数名を聞いてます。ここではデフォルトのままOnTestにし、OKボタンを押します。次に[コード編集]のボタンを押すと、追加されたメッセージ処理ルーチンが表示されましたね。
(Class View内で、CMainFrameを右クリックし「Windowsメッセージハンドラの追加」を選択しても追加できます。)

C処理のプログラミング
次に、処理を記述します。TODOの後に以下のコードを追加します。
void CMainFrame::OnTest() 
{
        // TODO: この位置にコマンド ハンドラ用のコードを追加してください
        CSubDlg         dlg;
        int                     ret;
        ret = dlg.DoModal();
}
最後に、CMainFrameのインクルードに以下の行を追加します。

#include "SubDlg.h"

以上で、メニュー項目とその処理が追加されました。ビルドして実行してみましょう。
追加したメニュー項目を選択してダイアログが表示されれば成功です。
■ ツール バーに追加したメニューのボタンを追加する
次に、ツールバーに前項で追加したメニュー項目のボタンを追加してみましょう。
ツール バーはユーザーが良く使うであろう項目をボタンにして選択をしやすくするためのものです。
ツールバーはボタンを作成して、IDを指定するだけでOKです。

ResourceView上でツールバーの項目の下にあるIDR_MAINFRAMEをダブルクリックして開きます。
これもメニューと同じく、SDIを作成した場合、自動的に作成されるデフォルトのツールバーです。これを自由に編集して使うことができます。
幾つかのボタンが表示されます。一番右に表示されているある空のボタンをダブルクリックして下さい。
ボタンの編集画面が現れましたね。ここに、好きな絵を書いてください。今回の例ではダイアログを表す絵を描きました。
この状態でツールバー上のこのボタンをダブルクリックすると、[ツール バー ボタン プロパティ]のダイアログが表示されます。
ここで、IDにID_TESTを選択してください。自動的にプロンプトが表示されるはずです。
これでダイアログを閉じてツールバー ボタンの追加完了です。
(ボタンをマウス左ボタンで少しドラック移動させることにより、隣のボタンとの隙間の有無を決めることができます。)

以上で、ツールバー追加完了です。ビルドして実行してみましょう。
追加したボタンを押してメニューと同じくダイアログが表示されれば成功です。
また、メニュー追加の時のプロンプトも確認してみてください。
■ サンプルプロジェクトファイルのダウンロード
(VC++6.0プロジェクトファイル22KB)