Version 18.01
ウィンドウプログラムをクラスで作る
「さて、今回が最終章になります!」
『と、とうとう最後……』
「この章では、 Version 8.01 ( No.143 ) から説明している、 API を使用
してダイアログを表示する、というプログラムを、クラスで作る説明をしま
す」
『んーと、あんときは WinMain() 関数とかダイアログプロシージャとか作
ったんだよね。あれをクラスで……ってことは、つまり普通の関数じゃなく
クラスで、ってこと?』
「そういうこと。今まで、ダイアログを含めてウィンドウプログラムを作る
という場合、以下の方法があります」
・ MFC を使用する方法
→メリット : MFC の膨大なクラスを使うことができる。
Class Wizard を使用してイベントハンドラを作れる。
→デメリット: MFC の仕組みをそのまま利用しなければいけない。
SDI 、 MDI は非常に複雑になり、「ドキュメント」
というものをどうしても使わざるを得ない。
・ API を使用する方法( MFC を使用しない方法)
→メリット :自由にプログラムを作ることができる。
MFC のような制約に縛られない。
→デメリット: MFC の便利なクラス( CString クラス等)を使えない。
イベント処理がぐちゃぐちゃになりやすい。
ダイアログの入力値の取得が面倒。
「 MFC のメリットのひとつは、はっきり言ってまず CString が使えるこ
と」
『確かに、 API だけの時は大変だったね色々と……』
「CString クラスといった便利なクラスを持っている、それがまず MFC の
メリット。加えて、ダイアログなら、ボタンで右クリックして【イベント】
でイベントハンドラが作れる手軽さ」
『そうなんだよねー、ボタンが押されたときの処理、って MFC だと簡単に
できるんだよね。 API だと Version 8.10 ( No.152 ) みたいに、
ダイアログプロシージャで if 使ってチェックしなきゃいけないのに』
「このイベント処理がわかりやすいのが MFC のメリット。でも MFC はあま
りにもしくみががっちりとしすぎていて、プログラムの柔軟性があまりない
んです」
『柔軟性?』
「まぁあることはあるんだけど、すごく複雑だったり、あとは SDI とかの
〈ドキュメント〉の存在かな。 Version 9.01 ( No.162 ) で説明したよう
に、 MFC には〈ドキュメント/ビューアーキテクチャー〉というものが
あるんです」
『ひとつのウィンドウにつきファイルひとつ、とかだっけ』
「そうそう。この仕組みが実はとても複雑でわかりにくいんです。ウィンドウ
とファイルは別々のものだからね」
『それがくっついちゃってるからわかりにくい、と』
「だからファイル操作は Version 5.09 ( No.074 ) で別に説明しているん
です」
『なるほどねー』
「 MFC を使うことで柔軟なプログラムが作れない、だから MFC を使わずに
API だけでプログラムを作る必要が出てくるんです」
『でも、デメリットもあると』
「まずは MFC が持ってる便利なクラスが使えない、っていう点。ただこれ
は回避方法があるから」
『え、あるの?』
「ファイル操作のところで説明した iostream 系のクラスを使う方法がある
から」
『じゃあそれはなんとかなる、と』
「で、もうひとつのデメリットは、イベント処理の問題。さっきも触れたけ
ど、たとえば【OKボタン】と【キャンセルボタン】が押された時の処理を
行う場合、 Version 8.10 ( No.152 ) の――」
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDOK )
{
// OK ボタンが押されました。
EndDialog( p_hDlgWnd, IDOK );
return TRUE;
}
else if( LOWORD( p_wParam ) == IDCANCEL )
{
// キャンセルボタンが押されました。
EndDialog( p_hDlgWnd, IDCANCEL );
return TRUE;
}
}
return FALSE;
}
「この DialogProc() 関数みたいに、ダイアログプロシージャの中で if 等
を使用して処理を分ける必要があるんです」
『これだとすぐごちゃごちゃしちゃうよね……』
「それに、この方法だと、たとえばダイアログで計算機アプリを作る場合、
エディットボックスに入力された整数値を取得する必要があるけど」
『あ、そか、 Class Wizard 使えないから……』
「 Version 3.10 ( No.035 ) みたいな、メンバ変数への自動変換とかはさ
れないから、自分でやらなきゃいけないってこと」
『うわ、これは面倒そう……』
「そこで、そういった部分をクラスを使ったり自分でクラスを作ったりして
何とかしよう、というのが今回の章の話」
『……クラスを作ってなんとかする?』
「ぶっちゃけていうと、 MFC みたいに、クラスでウィンドウ処理をするっ
てこと」
『! そんなことできるの??? まぁできるんだろうけど…… MFC は API
使ってるだけって何度も教わってるし……』
「もちろんそのまま同じものは作れないけど、必要最小限の機能を持ってい
て、かつ MFC よりも柔軟なウィンドウ処理用クラスを、実際に作ってみよう
というわけです」
『なんか本格的……』
「もちろん。これが最終章なんだから」
『あ、そうだった』
「さて、この章では、 Version 3.10 ( No.035 ) の計算機アプリを例題に
します」
『おお!』
「で、まずは API だけでそのプログラムを作ってみます」
『……それって結構大変なんじゃない?』
「そうでもないよ、これまでの知識をそのまま使えばいいだけだから。さて、
まずはプロジェクトを作ります」
『はーい』
「まず Version 8.01 ( No.143 ) と同じ方法で、 API 用プロジェクトを
作ります。メニューから【ファイル】−【新規作成】を選んで、
【プロジェクト】のページで【Win32 Application】を選びます」
『うんうん』
「プロジェクト名は〈NewCalc〉にして OK ボタンを押して、あとは
【空のプロジェクト】を選んで【終了】ボタンを押せば完了」
『ほいプロジェクトできた』
「次にソースファイルを追加します。メニューの【ファイル】−【新規作成】
を選んで、【C++ ソース ファイル】を選んで、ファイル名には Main.cpp で
OK ボタンを押してください」
『 Main.cpp ができて開いたよ』
「そこに以下のプログラムを書き込んでください」
#include <Windows.h>
#include <stdio.h>
#include "resource.h"
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDOK )
{
// OK ボタンが押されました。
EndDialog( p_hDlgWnd, IDOK );
return TRUE;
}
else if( LOWORD( p_wParam ) == IDC_B_EQUAL )
{
// 各エディットボックスのウィンドウハンドル
// を取得します。
HWND hLeftWnd
= GetDlgItem( p_hDlgWnd, IDC_E_LEFT );
HWND hRightWnd
= GetDlgItem( p_hDlgWnd, IDC_E_RIGHT );
HWND hAnswerWnd
= GetDlgItem( p_hDlgWnd, IDC_E_ANSWER );
// 各エディットボックス用文字列を用意します。
char pchLeft[256];
char pchRight[256];
char pchAnswer[256];
// IDC_E_LEFT と IDC_E_RIGHT の文字列を取得します。
GetWindowText( hLeftWnd, pchLeft, 255 );
GetWindowText( hRightWnd, pchRight, 255 );
// それぞれ int 型に変換します。
int iLeft = atoi( pchLeft );
int iRight = atoi( pchRight );
// 足した結果を pchAnswer に文字列変換します。
sprintf( pchAnswer, "%d", iLeft + iRight );
// それを IDC_E_ANSWER にセットします。
SetWindowText( hAnswerWnd, pchAnswer );
return TRUE;
}
}
return FALSE;
}
// WinMain() 。
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
int iRet
= DialogBox
( p_hInstance
, MAKEINTRESOURCE( IDD_MAIN )
, NULL
, DialogProc
);
return 0;
}
「で、次回に続く!」
『その前にちょっとお試し……』
「あ、これまだ完成してないから」
『ええっ!?』
/*
Preview Next Story!
*/
『うがーっ、ビルドしてもエラーになる!!』
「まだ足りない部分があるからね」
『足りない部分ってなにー!?』
「なんだと思う? 一応説明済みなんだけど」
『え”、えーっと……』
「というわけで次回」
< Version 18.02 計算機アプリを API だけで作る >
『につづく!』
「足りない部分があったみたいだね」
『げっ何そのしたり顔のオチは!!』