第13章 ダイアログボックス


今回は、ダイアログボックスの処理です。 必要な関数はDialogBoxとEndDialogです。 ところで、ダイアログボックス関係については 16ビットSDK32ビットSDKで 少し話が違ってきますのでまずは、32ビットの方を 中心に解説します。その後16ビット版での違いについても 触れます。

Win32 SDK

int DialogBox( HINSTANCE hInstance, // アプリケーションインスタンスハンドル LPCTSTR lpTemplate, // ダイアログボックステンプレート HWND hWndParent, // 親ウィンドウ DLGPROC lpDialogFunc // ダイアログプロシージャ );

これが32ビット版DialogBox関数です。 最初の引数はWinMain関数の第1引数と同じと考えてよい。 2番目の引数は、ダイアローグボックスのテンプレートの名前。 自分で作ったのならその名前を指定します。 3番目は、親ウィンドウの名前。最後は、このダイアログボックスの プロシージャ関数の名前。と簡単に覚えておきましょう。

さて、最初の引数ですがWinMain関数のところでグローバル変数に コピーしておくというのが最も簡単な方法です。 (他にもいろいろな方法があります。) 次が、ダイアログボックスの終了関数です。

BOOL EndDialog( HWND hDlg, // ダイアログボックスのウィンドウハンドル int nResult // DialogBoxへ戻す値 );

となっています。 では、さっそくプログラムを書いてみましょう。

// timer.cpp #include <windows.h> #include <time.h> #include <stdio.h> #include "timer.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE, LPCSTR); BOOL InitInstance(HINSTANCE, LPCSTR, int); int GetTimeStr(void); HINSTANCE hInst1; //インスタンスハンドル char time_str[256]="123"; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; char szClassName[] = "timer"; //ウィンドウクラス hInst1 = hCurInst; //グローバル変数にコピー if (!hPrevInst) { if (!InitApp(hCurInst, szClassName)) return FALSE; } if (!InitInstance(hCurInst, szClassName, nCmdShow)) { return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

ここまでは、前回までと殆ど同じです。ただ、hInst1というグローバル変数 を作って、hCurInstをコピーするのを付け加えただけです。 あとでこのhInst1が必要になってきます。 また、ダイアログプロシージャのプロトタイプ宣言をしています。

//ウィンドウ・クラスの登録  BOOL InitApp(HINSTANCE hInst, LPCSTR szClassName) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL/*"TIMERMENU"*/; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; return (RegisterClass(&wc)); }

ここも前回と同じです。

//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, LPCSTR szClassName, int nCmdShow) { HWND hWnd; HMENU hMenu; int i; hWnd = CreateWindow(szClassName, NULL, //タイトルバーにこの名前が表示されます WS_CAPTION | WS_SYSMENU, //ウィンドウの種類 9999, //X座標 9999, //Y座標 0, //幅 0, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, SW_MINIMIZE/*nCmdShow*/); UpdateWindow(hWnd); hMenu = GetSystemMenu(hWnd, FALSE); for (i = 0; i <= 5; i++) DeleteMenu(hMenu, 0, MF_BYPOSITION); AppendMenu(hMenu, MF_STRING, IDM_OPTION, "オプション"); DrawMenuBar(hWnd); return TRUE; }

ここでは、AppendMenu関数の3番目の引数と、4番目の引数を少し変えています。 したがって、ヘッダーファイルも修正する必要があります。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_SYSCOMMAND: switch (wp) { case IDM_OPTION: DialogBox(hInst1, "OPTDLG", hWnd, (DLGPROC)MyDlgProc); break; default: return(DefWindowProc(hWnd, msg, wp, lp)); break; } break; case WM_CREATE: if(SetTimer(hWnd, ID_MYTIMER, 1000, NULL) == 0) { MessageBox(hWnd, (LPCSTR)"タイマー失敗!", (LPCSTR)"失敗", MB_OK | MB_ICONEXCLAMATION); } break; case WM_TIMER: GetTimeStr(); SetWindowText(hWnd, (LPCSTR)time_str); break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if(KillTimer(hWnd, ID_MYTIMER) == TRUE) { MessageBox(hWnd, (LPCSTR)"タイマーを殺しました!", (LPCSTR)"タイマー削除の成功", MB_OK | MB_ICONEXCLAMATION); } DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

WM_SYSCOMMANDのIDM_OPTIONのところで、ダイアログボックス 関数を使っています。システムメニューのIDM_OPTIONが選ばれたら ダイアログボックスが出てくるという仕組みです。本来 この関数の戻り値でさらに処理を振り分けますが、ここでは 簡単のために、単にダイアログボックスを呼び出しているのみです。

LRESULT CALLBACK MyDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_INITDIALOG: return FALSE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: EndDialog(hDlgWnd, IDOK); break; case IDCANCEL: EndDialog(hDlgWnd, IDCANCEL); break; default: return FALSE; } default: return FALSE; } return TRUE; }

ここで、新しく出てきたダイアログボックスのプロシージャです。 ウィンドウプロシージャと似ていますね。WM_CREATEに相当するのが WM_INITDIALOGです。ここでは何もしないのでFALSEを返しています。 メッセージをきちんと処理したらTRUEを返すようにします。

int GetTimeStr(void) { char *str_org = "%2d時%2d分%2d秒"; time_t long_time; struct tm *now_time; time(&long_time); now_time = localtime(&long_time); sprintf(time_str, str_org, now_time->tm_hour, now_time->tm_min, now_time->tm_sec); return 0; }

現在時刻を文字列に整形する関数です。

// timer.h #define IDM_END 1000 #define IDM_OPTION 2000 #define IDC_STATIC 3000 #define ID_MYTIMER 32767

ヘッダーファイルはIDM_OPTIONを付け加えました。(IDM_TESTは削除)

また、ダイアログボックスのところで使うIDC_STATICを加えています。

ところで、まだダイアログボックスのリソース・スクリプト作ってないよ!!

はい。忘れていたわけではありません。 今回は、リソース・スクリプトは次のように打ち込んで下さい。次回説明します。

#include "windows.h" #include "timer.h" ////////////////////////////////////////////////////// // // Dialog // OPTDLG DIALOG DISCARDABLE 0, 0, 121, 69 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "オプション" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,38,50,14 PUSHBUTTON "キャンセル",IDCANCEL,61,37,50,14 LTEXT "オブションです。",IDC_STATIC,36,19,48,8 END

はい。これらをビルドして実行するとタスクバーに 時刻を表示するアイコンが出現します。 そして、それを右クリックしてシステムメニューを出し 「オプション」を選択すると

左のようなダイアログボックスが出現します。 (ただし、見た目はメッセージボックスと殆ど同じですね。)

Win16 SDK

次は、16ビット版の時の注意です。 32ビット版ではDialogBox関数の最後の引数は ダイアログプロシージャの名前を指定すればよかったのですが 16ビット版では少し違います。

static FARPROC fnDlgProc; ・・・・・・略 fnDlgProc = MakeProcInstance((FARPROC)DlgProc, hInst); ・・・・・・略 DialogBox(hInst, "MYDLG", hWnd, fnDlgProc);

という感じで使います。DialogBoxの最後の引数に 直接プロシージャの名前(アドレス)を指定してはいけません。 逆に32ビット版でこのように書いても問題はありません。
[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

Update Apr/04/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。