さて、リソース 、次にコンパイルするプログラム をやり、前回 はクラスの定義内容を解説しました。今回は前回の最後に書いたように「設計図 」で規定(宣言) される「メンバー関数 」の実装を行う(動作を行うコードを書く) 、CellProc.hを解説します。今回もSkeltonWizardが自動生成したコードではなく、手書きで弄っているところは紫色 で書きましょう。
【CellProc.h】
//////////////////////////////////////////
// CellProc.h
// Copyright (c) 08/04/2025 by BCCSkelton
//////////////////////////////////////////
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//ウィンドウメッセージ関数
/////////////////////////////////
bool CMyWnd::OnInit(WPARAM wParam, LPARAM lParam) {
//コモンコントロールの初期化
InitCommonControls();
//ツールバー登録-SetHandle(hWnd))
m_TBar.SetHandle(GetDlgItem(m_hWnd, IDC_TOOLBAR));
//ツールバーボタン用カスタムビットマップ追加
m_TBar.AddBmp(m_hInstance, MAKEINTRESOURCE(IDI_TOOLBAR), 6);
//ツールバーボタン追加
TBBUTTON tbb[9];
ZeroMemory(tbb, sizeof(tbb));
tbb[0].iBitmap = m_TBar.m_id + 0;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = TBSTYLE_BUTTON;
tbb[0].idCommand = IDM_OPEN;
tbb[1].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[2].iBitmap = m_TBar.m_id + 1;
tbb[2].fsState = TBSTATE_ENABLED;
tbb[2].fsStyle = TBSTYLE_BUTTON;
tbb[2].idCommand = IDM_EXIT;
tbb[3].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[4].iBitmap = m_TBar.m_id + 2;
tbb[4].fsState = TBSTATE_ENABLED;
tbb[4].fsStyle = TBSTYLE_BUTTON;
tbb[4].idCommand = IDM_START;
tbb[5].iBitmap = m_TBar.m_id + 3;
tbb[5].fsStyle = TBSTYLE_BUTTON;
tbb[5].idCommand = IDM_CELLS;
tbb[6].iBitmap = m_TBar.m_id + 4;
tbb[6].fsStyle = TBSTYLE_BUTTON;
tbb[6].idCommand = IDM_ABORT;
tbb[7].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[8].iBitmap = m_TBar.m_id + 5;
tbb[8].fsState = TBSTATE_ENABLED;
tbb[8].fsStyle = TBSTYLE_BUTTON;
tbb[8].idCommand = IDM_VERSION;
m_TBar.AddButtons(9, tbb);
//ステータスバー登録-SetHandle(hWnd))
m_SBar.SetHandle(GetDlgItem(m_hWnd, IDC_STATUSBAR));
//ステータスバー区画設定
int sec[3] = {70, 640, -1 }; //解説:左端から右端へのピクセル数です。-1は右端まで、という意味です。
m_SBar.SetSection(3, sec); //解説:SkeltonWizardで指定しました
//ステータスバー文字列設定
m_SBar.SetText(0, "Cell Ver 1.0"); //Ditto
// m_SBar.SetText(1, "(Time errupsed is shown here.)"); //解説:Times New Romanで書いた時は英語のみ
m_SBar.SetText(1, "(経過時間が表示されます) "); //解説:"Noto Serif JP Mediumに変えたので日本語へ
CARG Arg; //CARGクラスインスタンス( 解説:プログラムの引数を取得するオブジェクトです)
m_FileName = Arg.Path(); //解説:ダイアログの背景(地形)ファイルのファイルパスを記録するメンバー変数
m_FileName = m_FileName + "\\world_terrain.trn"; //解説:このファイル名を自動読み込みファイル名にしています
m_SBar.SetText(2, m_FileName.ToChar() );
m_SBar.SendMsg(SB_SETTIPTEXT, 2, (LPARAM)m_FileName.ToChar()); //ToolTipをつける
//仮想ウィンドウの初期化( 解説:メインダイアログに仮想ウィンドウ<描画用ビットマップ>を使います)
m_cvs.SetCanvas(m_hWnd);
//外部ビットマップを読みこむ(解説:その仮想ウィンドウに背景やセルのビットマップを貼り付けますー リソース 参照)
//地形は「野原:0」、「山:1」、「河川:2」、「食物:3」
m_Terrain_Bmp[0].LoadBMP(m_hWnd, "IDI_FIELD");
m_Terrain_Bmp[1].LoadBMP(m_hWnd, "IDI_MOUNT");
m_Terrain_Bmp[2].LoadBMP(m_hWnd, "IDI_RIVER");
m_Terrain_Bmp[3].LoadBMP(m_hWnd, "IDI_FOOD");
//cellはピンク、ブルー、グリーン、モノ(死亡)の4色
m_Cell_Bmp[0].LoadBMP(m_hWnd, "IDI_CELLP");
m_Cell_Bmp[1].LoadBMP(m_hWnd, "IDI_CELLB");
m_Cell_Bmp[2].LoadBMP(m_hWnd, "IDI_CELLG");
m_Cell_Bmp[3].LoadBMP(m_hWnd, "IDI_CELLD");
//m_PrevMapの初期化( 解説:これはWworldクラスのm_map配列変数の記録用で、"Previous map"という意味です)
fill(m_PrevMap, m_PrevMap + MAX_WIDTH * MAX_HEIGHT, -1); //解説:fill関数はメモリーの一定区間を指定値で埋めます
//背景表示
if(m_World.read_map(m_FileName.ToChar())) //解説:Cworldクラスの「背景ファイルの読み込み」メンバー関数です
ShowMap(); //解説:これは↓にあるユーザー関数です
else {
m_SBar.SetText(2, "");
m_SBar.SendMsg(SB_SETTIPTEXT, 2, (LPARAM)""); //ToolTipをつける
}
//Logフォールダーを作成する(既に存在するエラーは無視))
CreateDirectory(".\\Log", NULL); //解説:これはWin32API関数 です
return TRUE;
}
bool CMyWnd::OnTimer(WPARAM wParam, LPARAM lParam) {
//解説:ウィンドウズのWM_TIMERメッセージ処理 です
static int hours = 0; //解説:経過時間を静的変数で記録します(関連情報 )
//終了チェック
if(m_World.is_gameover()) { //解説:Wworldクラスのゲームが終了したか否かを確認するメンバー関数です
KillTimer(m_hWnd, ID_TIMER); //解説:タイマーを終了させ
m_Timer = FALSE; //解説:フラグを下ろします
// m_SBar.SetText(1, "Now Cell game is OVER!"); //解説:Times New Roman用英語
m_SBar.SetText(1, "Cellゲームが終了しました!");
// MessageBox(m_hWnd, m_World.get_message().c_str(), "Game Over Message", MB_OK | MB_ICONEXCLAMATION); //解説:Times New Roman用英語
MessageBox(m_hWnd, m_World.get_message().c_str(), "ゲーム終了通知", MB_OK | MB_ICONEXCLAMATION);
}
else {
//"Cell"ゲームの本体( 解説:このUIウィンドウプログラムで ゲームに関わる記述は次の一行 だけです)
m_World.goes_around(); //「世界」の中でセルが活動する
ShowMap(); //「世界」を表示する
//経過時間表示( 解説:↑のhours変数を使って経過時間を「年日時間」表示します)
int days = hours / 24;
int hh = hours % 24;
int yy = days / 365;
int dd = days % 365;
char str[32];
if(yy > 0)
// wsprintf(str, "%d years, %3d days and %2d hours", yy, dd, hh); //解説:Times New Roman用英語
wsprintf(str, "%d年、%3d日および%2d時間経過", yy, dd, hh);
else if(dd > 0)
// wsprintf(str, "%3d days and %2d hours", dd, hh); //解説:Times New Roman用英語
wsprintf(str, "%3d日及び%2d時間経過", dd, hh);
else
// wsprintf(str, "%2d hours", hh); //解説:Times New Roman用英語
wsprintf(str, "%2d時間経過", hh);
m_SBar.SetText(1, str);
hours++;
}
return FALSE; //WM_TIMERメッセージを処理するウィンドウプロシージャの戻り値は0
}
bool CMyWnd::OnNotify(WPARAM wParam, LPARAM lParam) {
//ツールバーからのツールチップ情報取得( 解説:ここの書き方は定番を再利用すると簡単です)
if(((LPNMHDR)lParam)->code == TTN_NEEDTEXT) {
static LPTOOLTIPTEXT lptip;
lptip = (LPTOOLTIPTEXT)lParam;
switch (lptip->hdr.idFrom) {
case IDM_OPEN:
lptip->lpszText = "ファイルを開く";
break;
case IDM_EXIT:
lptip->lpszText = "Cellの終了";
break;
case IDM_START:
lptip->lpszText = "ゲーム開始";
break;
case IDM_CELLS:
lptip->lpszText = "Cellの情報";
break;
case IDM_ABORT:
lptip->lpszText = "ゲーム中止";
break;
case IDM_VERSION:
lptip->lpszText = "バージョン情報";
break;
default:
return FALSE;
}
return TRUE;
}
return FALSE;
}
bool CMyWnd::OnPaint(WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT paint;
m_cvs.OnPaint(BeginPaint(m_hWnd, &paint)); //解説:CANVASクラスの描画です(SkeltonWizardが書いてくれました)
EndPaint(m_hWnd, &paint);
return TRUE;
}
bool CMyWnd::OnClose(WPARAM wParam, LPARAM lParam) {
if(MessageBox(m_hWnd, "終了しますか", "終了確認",
MB_YESNO | MB_ICONQUESTION) == IDYES) {
if(MessageBox(m_hWnd, "現在のセル状況を記録しますか?",
"ログ記録", MB_YESNO | MB_ICONQUESTION) == IDYES) {
m_World.make_log(); //終了時の全セルの状態をログに記録する
}
if(m_Timer) //WM_TIMER用
KillTimer(m_hWnd, ID_TIMER);
//処理をするとDestroyWindow、PostQuitMessageが呼ばれる
return TRUE;
}
else
//そうでなければウィンドウではDefWindowProc関数をreturn、ダイアログではreturn FALSEとなる。
return FALSE;
}
//ダイアログベースの場合はこれが必要
bool CMyWnd::OnDestroy(WPARAM wPram, LPARAM lParam) {
PostQuitMessage(0);
return TRUE;
}
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//メニュー項目、コントロール関数
/////////////////////////////////
bool CMyWnd::OnOpen() {
CSTR SourcePath; //解説:BCCSkelton版の文字列クラスです
CMNDLG cmndlg; //コモンダイアログ( 解説:コモンダイアログクラスをローカルインスタンスとして使用)
char* cp = cmndlg.GetFileName(m_hWnd, "地形ファイル(*.trn)\0*.trn\0\0", TRUE, "trn", "地形ファイルを開く");
if(!cp) {
MessageBox(m_hWnd, "ファイルの読み込みがキャンセルされました", "Error", MB_OK | MB_ICONERROR);
return FALSE;
}
else
m_FileName = cp;
//m_PrevMapの初期化
fill(m_PrevMap, m_PrevMap + MAX_WIDTH * MAX_HEIGHT, -1);
//地形図の読み込み
if(m_World.read_map(m_FileName.ToChar())) {
m_SBar.SetText(2, m_FileName.ToChar());
m_SBar.SendMsg(SB_SETTIPTEXT, 2, (LPARAM)m_FileName.ToChar()); //ToolTipをつける
ShowMap();
}
else {
m_SBar.SetText(2, "");
m_SBar.SendMsg(SB_SETTIPTEXT, 2, (LPARAM)""); //ToolTipをつける
}
return TRUE;
}
bool CMyWnd::OnExit() {
SendMsg(WM_CLOSE, 0, 0); //解説:定番のウィンドウを終了処理です
return TRUE;
}
bool CMyWnd::OnStart() {
//生成するcellの個数を取得する( 解説:ここでINPUTDLGのインスタンスを生成して使います)
inputdlg.DoModal(m_hWnd, "IDD_INPUT", inputdlgProc); //解説:入力用ダイアログを終了し
int n = inputdlg.GetSel(); //解説:ドロップダウンメニューの何番目を選択したか値を取得し
bool intmarg = inputdlg.IfIntMargOK(); //解説:異種族間婚の可否を確認して
m_World.create_cells(n, intmarg); //解説:Cworldクラスインスタンスのm_Worldにセルを生成します
ShowMap(); //解説:セル付きの画像を表示します
//メニュー、ツールバーボタン状態を変更( 解説:ユーザー関数を作って引数で一挙に状態を変えます)
ChangeMenuStatus(FALSE); //解説:↓を確認してください
//WM_TIMER用
if(!m_Timer) { //解説:タイマーが稼働中でなければ
if(!SetTimer(m_hWnd, ID_TIMER, TM_INTERVAL, NULL)) {
MessageBox(m_hWnd, "タイマー設定に失敗しました", "エラー", MB_OK | MB_ICONERROR);
}
else { //解説:タイマーが設定されたならばゲーム開始(OnTimerの処理参照)
m_Timer = TRUE;
// m_SBar.SetText(1, "Cell Game has just begun."); //解説:Times New Roman用英語
m_SBar.SetText(1, "Cellゲームが開始されました!");
}
}
else //解説:実際にはメニューやツールバーボタンを殺しているのでこの条件にはなりません
MessageBox(m_hWnd, "タイマーは既にオンです", "警告", MB_OK | MB_ICONEXCLAMATION);
return TRUE;
}
bool CMyWnd::OnCells() {
/* 解説:以下のコメントは、最初MessageBoxを使っていて表示できなくなり、
IDD_SHOWTEXTを作ることにして、それでも文字列が不足した経緯を書いています */
/* MessageBoxの出力文字数はUTF-16で1,024と言われているが、それではセル16個でも出力できない。
if(m_World.show_cell_param().length() > 1023)
MessageBox(m_hWnd, "セル数が多すぎて表示できません。\r\nファイル出力で見てください。",
"エラー", MB_OK | MB_ICONEXCLAMATION);
else
MessageBox(m_hWnd, m_World.show_cell_param().c_str(), "Cellの情報", MB_OK | MB_ICONINFORMATION);
try{
MessageBox(m_hWnd, m_World.show_cell_param().c_str(), "Cellの情報", MB_OK | MB_ICONINFORMATION);
throw "セル数が多すぎて表示できません。\r\nファイル出力で見てください。";
}
catch(char* errmsg) {
MessageBox(m_hWnd, errmsg, "エラー", MB_OK | MB_ICONEXCLAMATION);
}
その為、SHOWTEXTというダイアログを作ったが、EDITコントロールも32,767バイトの制限がある。
従って、予めそのチェックを行う。
*/
//解説:限度までは文字列表示ダイアログで示し、それ以上はエラーとしてメッセージボックスでデータと共に表示します
if(strlen(m_World.show_cell_param().c_str()) > 32767) {
int* dist = m_World.get_distribution();
char str[MAX_PATH];
wsprintf(str, "セル数が多すぎて表示できません。\r\n詳細はログファイルを確認してください。\r\n"\
"----------\r\nピンク セル:%d\r\nブルー セル:%d\r\nグリーンセル:%d\r\n"\
"死亡 セル:%d\r\n----------\r\n合計 :%d",
dist[0], dist[1], dist[2], dist[3], dist[0] + dist[1] + dist[2] + dist[3]);
MessageBox(m_hWnd, str, "エラー", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
showtextdlg.m_Output = (char*)m_World.show_cell_param().c_str();
showtextdlg.DoModal(m_hWnd, "IDD_SHOWTEXT", showtextdlgProc);
return TRUE;
}
bool CMyWnd::OnAbort() {
//ゲーム終了処理( 解説:「強制終了」あるいは「中断」、ですね)
m_World.gameover(); //Cworldのm_gameoverフラグをtrueにする
//WM_TIMER用( 解説:タイマーを停止し、フラグも下ろします)
KillTimer(m_hWnd, ID_TIMER);
m_Timer = FALSE;
// m_SBar.SetText(1, "Cell Game is aborted."); //解説:Times New Roman用英語
m_SBar.SetText(1, "Cellゲームが中断されました!");
//ゲームログの保存
if(MessageBox(m_hWnd, "現在のセル状況を記録しますか?", "ログ記録",
MB_YESNO | MB_ICONQUESTION) == IDYES) {
m_World.make_log(); //終了時の全セルの状態をログに記録する
}
//m_Worldを初期化
m_World.init();
if(MessageBox(m_hWnd, "現在選択されている地形図を読み込みますか?(はい)"\
"\r\nまたは「ファイルを開く」で指定ファイルを選択しますか?(いいえ)",
"地形図の確認", MB_YESNO | MB_ICONQUESTION) == IDYES) {
//m_PrevMapの初期化
fill(m_PrevMap, m_PrevMap + MAX_WIDTH * MAX_HEIGHT, -1);
//現在選択されている地形図の読み込み
if(m_World.read_map(m_FileName.ToChar())) {
m_SBar.SetText(2, m_FileName.ToChar());
m_SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)m_FileName.ToChar()); //ToolTipをつける
ShowMap();
}
else {
m_SBar.SetText(1, "");
m_SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)""); //ToolTipをつける
}
}
else { //ファイルの読み込み
OnOpen();
}
//メニュー、ツールバーボタン状態を変更
ChangeMenuStatus(TRUE);
return TRUE;
}
bool CMyWnd::OnVersion() {
/* 解説:以下はメインダイアログのフォントをTimes New RomanからNoto Serif JPに
変更した際に縦横比が変わった為、実際にウィンドウを動かしてサイズ合わせをした
際のコードです。*/
/* メインダイアログ関連サイズチェックテスト
RECT rec;
GetWindowRect(m_hWnd, &rec); //メインダイアログのサイズ取得
int dlgW = (rec.right - rec.left);
int dlgH = (rec.bottom - rec.top);
GetClientRect(m_hWnd, &rec); //メインダイアログクライアントエリアのサイズ取得
int cltW = (rec.right - rec.left);
int cltH = (rec.bottom - rec.top);
GetWindowRect(m_TBar.GetHandle(), &rec); //ツールバー高さ取得
int TBH = (rec.bottom - rec.top);
GetWindowRect(m_SBar.GetHandle(), &rec); //ステータスバー高さ取得
int SBH = (rec.bottom - rec.top);
char buff[MAX_PATH];
wsprintf(buff, "メインダイアログの幅:%d\r\nメインダイアログの高さ:%d\r\nクライアントエリアの幅:%d\r\nクライアントエリアの高さ:%d\r\nツールバーの高さ:%d\r\nステータスバーの高さ:%d\r\n", dlgW, dlgH, cltW, cltH, TBH, SBH);
MessageBox(m_hWnd, buff, "サイズ情報", MB_OK | MB_ICONINFORMATION);
*/
versiondlg.DoModal(m_hWnd, "IDD_VERSION", versiondlgProc); //解説:バージョンダイアログの表示
return TRUE;
}
///////////////////
//ユーザー定義関数
///////////////////
//背景(m_map)を表示する
/* 解説:マップの描画速度を上げるために、
(1)Cworldクラスインスタンスのm_Worldのm_mapのデータを描画の際にm_PrevMapに記録し、
(2)m_PrevMapとm_mapの差異があるときのみ、ビットマップを全部仮想ウィンドウに書き込み、
(3)「変更フラグ」で差異がある時のみ、仮想ウィンドウを更新(更新描画)する
ようにしています */
void CMyWnd::ShowMap() {
bool changed = false; //m_Worldのマップとm_PrevMapとの差異フラグ
for(int j = 0; j < MAX_HEIGHT; j++) { //Y座標
for(int i = 0; i < MAX_WIDTH; i++) { //X座標
//ビットマップ表示(m_cvs、m_Terrain_Bmp[]はCMyWndのメンバー変数)
int n = m_World.check_what(i, j); //(i, j)の位置に何があるか
if(m_PrevMap[MAX_WIDTH * j + i] != n) { //前回から変更があれば
m_PrevMap[MAX_WIDTH * j + i] = n; //記録して
changed = true; //差異フラグを立てる
}
Ccell *cell; //Cellのポインター
switch(n) {
case 0: //野原
case 1: //山
case 2: //河川
case 3: //食物
if(changed) //前回から変更があれば(解説:背景に変更はないのですが...為念)
PutBMP(m_Terrain_Bmp[n].Handle(), i * 16, j * 16 + TBarH);
break;
default: //解説:セルの場合と誤入力の場合を想定しています
if(n > 3) { //Cell(4 + m_id)の場合、同じCellでも「生死」変化があり得る
cell = m_World.get_cell(i, j); //(i, j)の位置あるCellのポインターを取得
PutBMP(m_Cell_Bmp[cell->get_tribe()].Handle(), i * 16, j * 16 + TBarH);
//解説:セルビットマップ配列(m_Cell_Bmp)に引数は種族(含死亡セル)
}
else if(n == -1)
MessageBox(m_hWnd, "地形ファイル(*.trn)に許容されない文字が含まれています。",
"エラー", MB_OK | MB_ICONERROR);
break;
}
}
}
if(changed) { //変化が一つでもあれば、背景を消去してバー以外のクライアント領域を更新
RECT rec = {0, TBarH, MAX_WIDTH * 16, MAX_WIDTH * 16 - TBarH - SBarH};
InvalidateRect(m_hWnd, &rec, FALSE); //解説:Invalidate(無効にする)関数の解説はこちら
}
}
//ビットマップ画像貼付け
//解説:BCCSkeltonのCBMPクラスの同名関数から「再描画処理」を外したものです
// 理由は、一つ一つのビットマップで再描画するとちらつきが発生するからです
bool CMyWnd::PutBMP(HBITMAP bmp, int x, int y) {
if(!bmp) //有効なビットマップが無ければ
return FALSE; //偽を返す
HDC hDC = GetDC(m_hWnd); //ウィンドウDCを取得
HDC memDC = CreateCompatibleDC(hDC); //コンパチDCを作成
SelectObject(memDC, bmp); //ビットマップを選択
BITMAP bm; //BITMAP構造体
GetObject(bmp, sizeof(BITMAP), &bm); //サイズをszに取り出す
bool success = BitBlt(m_cvs.hDC(), x, y, bm.bmWidth, bm.bmHeight, memDC, 0, 0, SRCCOPY);
ReleaseDC(m_hWnd, hDC); //ウィンドウDCを開放
DeleteObject(memDC); //コンパチDCを削除
return success;
}
// メニュー、ツールバー状態の変更
void CMyWnd::ChangeMenuStatus(bool EnableFlag) {
//解説:定番のメニュー、ツールバーボタンの有無効化処理です
HMENU hMenu = GetMenu(Cell.GetHandle()); //メニューハンドルの取得
HMENU hFileMenu = GetSubMenu(hMenu, 0); //ファイルメニューハンドルの取得
HMENU hGameMenu = GetSubMenu(hMenu, 1); //ゲームメニューハンドルの取得
EnableMenuItem(hFileMenu, IDM_OPEN, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hGameMenu, IDM_START, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hGameMenu, IDM_CELLS, MF_BYCOMMAND | (EnableFlag ? MF_GRAYED : MF_ENABLED));
EnableMenuItem(hGameMenu, IDM_ABORT, MF_BYCOMMAND | (EnableFlag ? MF_GRAYED : MF_ENABLED));
DrawMenuBar(Cell.GetHandle());
//ツールバー(MAKELONGマクロは16bit整数2つをunsigned 32bit整数にする)
SendMessage(m_TBar.GetHandle(), TB_ENABLEBUTTON, IDM_OPEN, MAKELONG(EnableFlag, 0));
SendMessage(m_TBar.GetHandle(), TB_ENABLEBUTTON, IDM_START, MAKELONG(EnableFlag, 0));
SendMessage(m_TBar.GetHandle(), TB_ENABLEBUTTON, IDM_CELLS, MAKELONG(!EnableFlag, 0));
SendMessage(m_TBar.GetHandle(), TB_ENABLEBUTTON, IDM_ABORT, MAKELONG(!EnableFlag, 0));
}
///////////////////////////////
//ユーザーダイアログの関数定義
//コントロール関数
///////////////////////////////
/////////////////////////
//IDD_INPUT ダイアログ
/////////////////////////
bool INPUTDLG::OnInit(WPARAM wParam, LPARAM lParam) {
//コンボボックスの初期設定(解説:8の倍数にして、64個迄にしたのはテスト経験によります)
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 0, (LPARAM)"8 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 1, (LPARAM)"16 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 2, (LPARAM)"24 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 3, (LPARAM)"32 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 4, (LPARAM)"40 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 5, (LPARAM)"48 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 6, (LPARAM)"56 cells");
SendItemMsg(IDC_COMBOBOX, CB_INSERTSTRING, 7, (LPARAM)"64 cells");
return TRUE;
}
bool INPUTDLG::OnIdok() {
//コンボボックスの選択確認
if((m_Sel = SendItemMsg(IDC_COMBOBOX, CB_GETCURSEL, 0, 0)) == CB_ERR) {
MessageBox(m_hWnd, "コンボボックスが選択されていません", "エラー", MB_OK | MB_ICONERROR);
return FALSE;
}
else
++m_Sel *= 8; //解説:この変な算式は①先ずm_Selを一つインクリメントして、②8倍するということです
//異種族間婚許容チェックボックス確認
if(SendItemMsg(IDC_INTMARG, BM_GETCHECK, 0, 0) == BST_CHECKED)
m_IntMarg = TRUE;
else
m_IntMarg = FALSE;
EndModal(TRUE);
return TRUE;
}
bool INPUTDLG::OnCancel() {
EndModal(FALSE);
return TRUE;
}
/////////////////////////
//IDD_SHOWTEXT ダイアログ
/////////////////////////
bool SHOWTEXTDLG::OnInit(WPARAM wParam, LPARAM lParam) {
//エディットコントロールの最大文字数(32,767)の設定(解説:これが最大文字数です)
SendItemMsg(IDC_EDIT, EM_SETLIMITTEXT, 32767, 0);
//エディットコントロールのテキスト表示
SendItemMsg(IDC_EDIT, WM_SETTEXT, 0, (LPARAM)m_Output);
/* 解説:このままだとテキストが「全選択」状態になるので、以下の仕様を踏まえ、
先頭にキャレットを移動しています。*/
// WM_INITDIALOGで次の動作を行っても全文選択状態は解消できない
// SetFocus(GetDlgItem(m_hWnd, IDC_EDIT));
// SendItemMsg(IDC_EDIT, EM_SETSEL, 0, 0);
// その為、メッセージキューに流して時間稼ぎを行う。
PostMessage(GetDlgItem(m_hWnd, IDC_EDIT), WM_SETFOCUS, (WPARAM)GetDlgItem(m_hWnd, IDC_EDIT), 0);
PostMessage(GetDlgItem(m_hWnd, IDC_EDIT), EM_SETSEL, 0, 0);
return TRUE;
}
bool SHOWTEXTDLG::OnSize(WPARAM wParam, LPARAM lParam) {
//コントロール位置調整
//解説:このダイアログはサイズ可変なので、大きさを変えてもコントロールが追従するようにしています
MoveWindow(GetDlgItem(m_hWnd, IDC_EDIT), 7, 8, LOWORD(lParam) - 14, HIWORD(lParam) - 48, TRUE);
MoveWindow(GetDlgItem(m_hWnd, IDOK), (LOWORD(lParam) - 70) / 2, HIWORD(lParam) - 32, 70, 24, TRUE);
return TRUE;
}
bool SHOWTEXTDLG::OnIdok() {
//解説:↑のOnSize処理のためにサイズをモニタリングしました
/*
RECT rec;
GetWindowRect(m_hWnd, &rec); //ダイアログのサイズ取得
int dlgW = (rec.right - rec.left);
int dlgH = (rec.bottom - rec.top);
GetClientRect(m_hWnd, &rec); //ダイアログクライアントエリアのサイズ取得
int cltW = (rec.right - rec.left);
int cltH = (rec.bottom - rec.top);
GetWindowRect(GetDlgItem(m_hWnd, IDC_EDIT), &rec); //ボタンのサイズ取得
int edtW = (rec.right - rec.left);
int edtH = (rec.bottom - rec.top);
GetWindowRect(GetDlgItem(m_hWnd, IDOK), &rec); //ボタンのサイズ取得
int btnW = (rec.right - rec.left);
int btnH = (rec.bottom - rec.top);
char buff[MAX_PATH];
wsprintf(buff, "ダイアログの幅:%d\r\nダイアログの高さ:%d\r\nクライアントエリアの幅:%d\r\nクライアントエリアの高さ:%d\r\nEDITの幅:%d\r\nEDITの高さ:%d\r\nボタンの幅:%d\r\nボタンの高さ:%d", dlgW, dlgH, cltW, cltH, edtW, edtH, btnW, btnH);
MessageBox(m_hWnd, buff, "サイズ情報", MB_OK | MB_ICONINFORMATION);
*/
EndModal(TRUE);
return TRUE;
}
bool SHOWTEXTDLG::OnCancel() {
EndModal(FALSE);
return TRUE;
}
/////////////////////////
//IDD_VERSION ダイアログ(解説:このレイアウトが好きなので、使い廻ししています )
/////////////////////////
bool VERSIONDLG::OnIdok() {
EndModal(TRUE);
return TRUE;
}
bool VERSIONDLG::OnCancel() {
EndModal(FALSE);
return TRUE;
}
さーて、いかがだったでしょうか?C++プログラミングは矢張りコード量が多いので目と頭が疲れますね。
しかしっ
ここ迄のコードは単にUI ウィンドウ(私の言葉でいう
「ドンガラ」
)のものでしかないので、やっとUI を離れて、これからOnTimerにあるゲーム進行関数(m_World.goes_around(); //「世界」の中でセルが活動する )を含む"Ccell_world.h"に移ることにします。