第288章 状況依存ヘルプ


今回は状況依存ヘルプをやります。前準備としてHTMLヘルプを作るときに 各トピックにコンテキスト番号を割り当てておく必要があります。 そして、この時作ったヘッダファイルが必要となります。 これは、番外編 第3章を参照してください。



メニュー項目がアクティブになっている時(文字が反転強調されます)、F1キーを押すと それに関連したヘルプが出ます。左の図では「ダイアログボックス(D)」 というメニュー項目がアクティブになっているのでこの時F1キーを 押すと、これに関連したヘルプが出てきます。

また、クライアント領域にボタンがありますが、これがフォーカスを持っている時 (ボタンの内側が点線で囲まれます)F1キーを押しても、これに関連した ヘルプが出てきます。



メニューの「ダイアログボックス」を選択すると、左の図のようなダイアログが 出てきます。この時右上に「?」マークのボタンがついていることに注意してください。

このボタンを押すとマウスカーソルが矢印と「?」マークがくっついた形状に変わります。 この状態で「氏名」「住所」などのスタティックコントロールや、エディットコントロール、 「OK」「キャンセル」ボタンをクリックするとそれぞれの説明が書かれたヘルプまたは、 メッセージボックスが出てきます。



では、その仕組みはどうなっているのでしょうか。

ユーザーがF1キーを押すとWM_HELPメッセージが来ます。また、?印カーソルが クリックされたときもWM_HELPメッセージが来ます。

WM_HELP lphi = (LPHELPINFO) lParam;

この時lParamは、HELPINFO構造体のアドレスを表します。

HELPINFO構造体は、次のように定義されています。

typedef struct tagHELPINFO { UINT cbSize; int iContextType int iCtrlId; HANDLE hItemHandle; DWORD dwContextId; POINT MousePos; } HELPINFO, FAR *LPHELPINFO;

cbSizeは、この構造体のサイズを表します。

iContextTypeは、要求されているヘルプのコンテキストの種類を表します。次のうちの 1つです。

HELPINFO_MENUITEMメニュー項目に対するヘルプが要求されている
HELPINFO_WINDOWコントロールまたはウィンドウに対するヘルプが要求されている

iCtrlIdは、iContextTypeがHELPINFO_WINDOWの時はウィンドウまたはコントロールのIDを 表します。
iContextTypeがHELPINFO_MENUITEMの時はメニュー項目のIDを表します。

hItemHandleは、iContextTypeがHELPINFO_WINDOWの時は子ウィンドウ、またはコントロールの ウィンドウハンドルを表します。
iContextTypeがHELPINFO_MENUITEMの時は、メニュー項目のIDを表します。

dwContextIdは、ウィンドウまたはコントロールのコンテキストIDを表します。

MousePosは、マウスカーソルの座標のPOINT構造体です。

ついでにWM_CONTEXTMENUというメッセージの復習もしておいてください。 普段あまり使わないので忘れがちです。忘れた人は 第115章を参照してください。

では、プログラムを見てみましょう。

// help04.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "ダイアログボックス(&D)", IDM_DLG END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 130, 73 STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "オプション" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,52,50,14 PUSHBUTTON "キャンセル",IDCANCEL,73,52,50,14 LTEXT "氏名",IDC_STATIC1,14,13,24,12 LTEXT "住所",IDC_STATIC2,15,35,26,11 EDITTEXT IDC_EDIT1,63,7,59,17,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,62,31,59,16,ES_AUTOHSCROLL END

メニューと、ダイアログボックスのリソース・スクリプトです。 ダイアログボックスのスタイルにDS_CONTEXTHELP が含まれていることに注意してください。これで、ダイアログボックスの右上に 「?」マークのボタンが追加されます。VC++のリソースエディタでは ダイアログプロパティの「その他のスタイル」の「コンテキストヘルプ」に チェックを付けておきます。

このほかにHTMLヘルプを作ったときのコンテキストIDに番号をdefineした ヘッダファイル(test.h, 番外編第3章参照) も必要です。

// help04.cpp #ifndef STRICT #define STRICT #endif #define ID_BUTTON 100 #include <windows.h> #include "resource.h" #include "htmlhelp.h" #include "test.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "help04"; //ウィンドウクラス HINSTANCE hInst; DWORD dwCookie; //クッキー

HTMLヘルプAPIを使うときの前準備を忘れないでください。 また、test.hのインクルードはコンテキストIDを使うときに必要です。 ボタンのIDをdefineしている点にも注意してください。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; // ヘルプシステムの初期化 HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie); while (GetMessage(&msg, NULL, 0, 0)) { if (!HtmlHelp(NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD)&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; }

インスタンスハンドルをグローバル変数にコピーしている点に注意してください。

HTMLヘルプを使うときの初期化とメッセージループの処理に注意してください。

//ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); 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 = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるヘルプ", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

このへんはいつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HELPINFO *lphi; static HWND hBut; switch (msg) { case WM_CREATE: hBut = CreateWindow("Button", "テスト", WS_VISIBLE | WS_CHILD, 10, 10, 60, 25, hWnd, (HMENU)ID_BUTTON, hInst, NULL); SetFocus(hBut); break; case WM_HELP: lphi = (HELPINFO *)lp; switch (lphi->iCtrlId) { case IDM_END: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO5); break; case IDM_DLG: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO6); break; case ID_BUTTON: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO7); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_DLG: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hBut); DestroyWindow(hWnd); } break; case WM_DESTROY: HtmlHelp(NULL, NULL, HH_UNINITIALIZE, (DWORD)dwCookie); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

親ウィンドウのプロシージャです。

WM_CREATEメッセージが来たらボタンを作っています。そして、フォーカスを セットしています。

WM_HELPメッセージが来たらHELPINFO構造体のiCtrlIDメンバで場合分けしています。
メニューのIDM_ENDでF1が押されたらIHD_NO5に関連づけられたトピックを表示します。
IDM_DLGでF1が押されたときはIHD_NO6を表示します。
ボタンにフォーカスがあるときにF1が押されたときはIHD_NO7を表示します。

HH_HELP_CONTEXT コマンド pszFileには、マップ情報を持ったchmファイルを指定します。ウィンドウタイプを 指定する場合は>記号のあとにウィンドウタイプの名前を指定します。

dwDataには、表示したいトピックのコンテキストIDを指定します。

メニューからIDM_DLGが選択されたときは、ダイアログボックスを表示します。

プログラム終了時HH_UNINITIALIZEコマンドの実行を忘れないでください。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { HELPINFO *lphi; switch (msg) { case WM_HELP: lphi = (HELPINFO *)lp; switch (lphi->iCtrlId) { case IDOK: MessageBox(hDlg, "OKボタンです", "OK", MB_OK); return TRUE; case IDCANCEL: MessageBox(hDlg, "Cancel ボタンです", "OK", MB_OK); return TRUE; case IDC_STATIC1: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO1); return TRUE; case IDC_STATIC2: HtmlHelp(hDlg, "test.chm", HH_HELP_CONTEXT, IDH_NO2); return TRUE; case IDC_EDIT1: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO3); return TRUE; case IDC_EDIT2: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO4); return TRUE; } return FALSE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: case IDCANCEL: EndDialog(hDlg, IDOK); return TRUE; } return FALSE; } return FALSE; }

ダイアログボックスのプロシージャです。

「?」印カーソルがクリックされたときHELPINFO構造体のiCtrlIDメンバで場合分けしています。

OKボタンとキャンセルボタンでクリックしたときはヘルプではなく、メッセージボックスを 出すようにしています。

今回は簡単なプログラムですが、使い道は広いです。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

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