今回は、プロパティシートを作成します。
下図のような、ダイアログボックスのメニューから「プロパティ」を選択すると、 プロパティシートが立ち上げるようにします。
テキストの表示 - インコのWindowsSDK で作成したソースを修正します。
流れ
プロパティシートは、コモンコントロールのひとつです。コモンコントロールは他にも、ツリービューやリストビュー、ツールバーなどがあります。
コモンコントロールを使う場合は、下記1、2の両方を行って下さい。
1.commctrl.h をインクルード
2.comctl32.lib を読み込む
3.Windows 2000で動作できるアプリケーションを作成する場合は、
#define _WIN32_WINNT 0x0500
を追加。0x0500はWindows 2000を示します。
これは、後で説明するPROPSHEETPAGE構造体がWindows XPで追加されたためです。
Visual C++ 2010の場合は、作成したアプリケーションがWindows 2000で動作しないため、これを追加する必要はありません。
WM_INITDIALOG
リストボックス - インコのWindowsSDK でも説明しましたが、WM_INITDIALOGは、ダイアログが作成されたときに一度だけ実行されます。
1.InitCommonControls()でコモンコントロールの初期化
コモンコントロールを使う前にこの初期化が必要です。
WM_COMMAND
1.「プロパティ」をメニューから選択された場合、WM_COMMANDメッセージが発生します。
1.1.プロパティシートを作成します。まずは、PROPSHEETPAGE構造体をセット
typedef struct _PROPSHEETPAGE { DWORD dwSize; DWORD dwFlags; HINSTANCE hInstance; union { LPCSTR pszTemplate; LPCDLGTEMPLATE pResource; }; union { HICON hIcon; LPCSTR pszIcon; }; LPCSTR pszTitle; DLGPROC pfnDlgProc; LPARAM lParam; LPFNPSPCALLBACK pfnCallback; UINT *pcRefParent; LPCTSTR pszHeaderTitle; LPCTSTR pszHeaderSubTitle; #if (_WIN32_WINNT >= 0x0501) // Windows XP以上 HANDLE hActCtx; #endif } PROPSHEETPAGE, *LPPROPSHEETPAGE;
構造体のメンバ | 意味 | |
dwSize | この構造体のサイズ sizeof(PROPSHEETPAGE)をセットします。 |
|
dwFlags | フラグ | |
PSP_DEFAULT | 構造体の全てのメンバに対し、デフォルト値を使用 | |
PSP_HASHELP | 「ヘルプ」ボタンを使用可能にします | |
PSP_USEHICON | ページタブの小さなアイコンとして hIcon (ハンドル)を使用 | |
PSP_USEICONID | ページタブの小さなアイコンとして pszIcon (リソース)を使用 | |
PSP_USETITLE | ダイアログのタイトルに pszTitle を使用 デフォルトでは、ダイアログボックステンプレートのタイトルが使用 |
|
hInstance | ダイアログボックステンプレートなどのリソースが格納されている モジュールのインスタンスハンドル | |
pszTemplate | ダイアログボックステンプレートのID | |
hIcon | ページのタブの小さなアイコンとして用いるアイコンのハンドル PSP_USEICON フラグが設定されていなければ、このメンバは無視 |
|
pszIcon | ページのタブの小さなアイコンとして用いるアイコンのID (タブのアイコンをリソースから取得する場合) PSP_USEICONID フラグが設定されていなければ、このメンバは無視 |
|
pszTitle | ページのタイトルとなる文字列、またはリソースID PSP_USETITLE フラグが設定されていなければ、このメンバは無視 |
|
pfnDlgProc | ページダイアログのダイアログプロシージャへのポインタ | |
lParam | ページダイアログのダイアログプロシージャに渡したいデータ | |
pfnCallback | LPFNPSPCALLBACK 型コールバック関数のポインタ このコールバック関数は、ページが作成されたり、破棄される時に呼び出されます |
1.2.CreatePropertySheetPage()でプロパティシートの新しいページを作成します。
この関数の引数に、PROPSHEETPAGE構造体をセットしてください。
CreatePropertySheetPage()の戻り値は、プロパティシートの作成した新しいページのハンドルですので、これをHPROPSHEETPAGE型の配列に保存します。
1.3.PROPSHEETHEADER構造体をセット
typedef struct _PROPSHEETHEADER { DWORD dwSize; DWORD dwFlags; HWND hwndParent; HINSTANCE hInstance; union { HICON hIcon; LPCTSTR pszIcon; }; LPCTSTR pszCaption; UINT nPages; union { UINT nStartPage; LPCTSTR pStartPage; }; union { LPCPROPSHEETPAGE ppsp; HPROPSHEETPAGE *phpage; }; PFNPROPSHEETCALLBACK pfnCallback; union { HBITMAP hbmWatermark; LPCTSTR pszbmWatermark; }; HPALETTE hplWatermark; union { HBITMAP hbmHeader; LPCSTR pszbmHeader; }; } PROPSHEETHEADER, *LPPROPSHEETHEADER;
構造体のメンバ | 意味 | |
dwSize | この構造体のサイズ sizeof(PROPSHEETHEADER)をセットします。 |
|
dwFlags | フラグ | |
PSH_DEFAULT | 構造体の全てのメンバに対し、デフォルト値を使用 | |
PSH_HASHHELP | 「ヘルプ」ボタンを使用可能にします。 | |
PSH_MODELESS | モードレスダイアログボックスのプロパティシートを作成 | |
PSH_MULTILINETABS | 複数行表示のタブを使用 | |
PSH_NOAPPLYNOW | 「適用」ボタンを削除 | |
PSH_PROPTITLE | pszCaption で指定された文字列を プロパティシートのタイトルとして使用 | |
PSH_USECALLBACK | プロパティシートを初期化する時 pfnCallbackで指定した関数を呼び出します | |
PSH_USEHICON | プロパティシートダイアログボックスのアイコンとして hIcon (ハンドル)を使用 | |
PSH_USEHICON | プロパティシートダイアログボックスのアイコンとして pszIcon (リソース)を使用 | |
PSH_WIZARD | ウィザードプロパティシートを作成 | |
hwndParent | 親ウィンドウのハンドル | |
hInstance | リソースを含むモジュールのインスタンスハンドルを指定 リソースからアイコンなどを読み込む場合は、必ず指定 |
|
hIcon | プロパティシートのタイトルバーに表示するアイコンのハンドル PSH_USEHICON フラグが設定されていなければ、このメンバは無視 |
|
pszIcon | タイトルバーに表示するアイコンのID PSH_USEICONID フラグが設定されていなければ、このメンバは無視 |
|
pszCaption | ページのタイトルとなる文字列、またはリソースID | |
nPages | phpage メンバが指す配列内にある要素の数 | |
nStartPage | プロパティシートを作成した時、初期時に表示するページ番号 | |
ppsp | プロパティシートの各ページを定義した PROPSHEETPAGE 構造体の配列へのポインタ | |
phpage | 各ページのハンドルの配列へのポインタを指定 | |
pfnCallback | PFNPROPSHEETCALLBACK 型コールバック関数のポインタ このコールバック関数は、プロパティシート初期化時に呼び出されます |
|
hwndDlg | プロパティシートダイアログボックスのハンドル |
1.4.PropertySheet()でプロパティシートの作成
int PropertySheet(LPCPROPSHEETHEADER lppsph);
lppsph | PROPSHEETHEADER 構造体へのポインタ |
プロパティシートのコールバック関数
プロパティシートは、タブごとにコールバック関数が必要です。
コールバック関数とは、プログラム中で、呼び出し先の関数の実行中に実行されるように、あらかじめ指定しておく関数のことです。
1.WM_INITDIALOG
SetWindowText()で、表示する文字列を、テキストボックスにセット
● WM_NOTIFYメッセージとは、
WM_NOTIFYメッセージは、コモンコントロールでイベントが起こった場合、およびコモンコントロールが情報を親ウィンドウに要求する場合に、コモンコントロールの親ウィンドウに送信されます。
・WM_NOTIFYメッセージ発生時の wParam [コールバック関数の第3引数]の値・・・
イベントが発生したコモンコントロールのコントロールID
・WM_NOTIFYメッセージ発生時の lParam [コールバック関数の第4引数]の値・・・
NMHDR構造体、あるいはNMHDR構造体を最初のメンバに持つ構造体のアドレス
NMHDR構造体のidFromメンバが コントロールIDと同じかどうかで、メッセージを識別します。
typedef struct tagNMHDR { HWND hwndFrom; // コントロールのハンドル UINT idFrom; // コントロールID UINT code; // 通知コード } NMHDR;
WM_NOTIFYメッセージのlParamである NMHDR構造体の hwndFromメンバ、もしくは idFromメンバで、コントロールを識別します。
NMHDR構造体のcodeメンバが「通知コード」です。この通知コードが発生したメッセージになります。
・ WM_NOTIFYメッセージを使った、分かりにくい仕様になった理由
WM_からはじまるメッセージに追加しないで、WM_NOTIFYメッセージを使ったややこしい仕様になったのは、
もともとWM_からはじまるメッセージが 0x0400 までしか追加できない仕様になっており、WM_からはじまるメッセージの数が増えすぎて、追加できなくなったからだと思われます。
実際、Visual C++ 2010の WinUser.h を見てみますと、すでに0x038Fまで使用しています。
● 今回のアプリケーションでの使用方法
今回の場合、ユーザーが「OK」ボタンを押すと、ダイアログプロシージャにWM_NOTIFYメッセージが送信されます。 NMHDR構造体の通知コードは PSN_APPLYになります。
NMHDR構造体nmhdrの通知コードcode [nmhdr->code] が PSN_APPLY のとき、GetWindowText()で、テキストボックスから文字列を取得します。
int GetWindowText( HWND hWnd, // ウィンドウまたはコントロールのハンドル LPTSTR lpString, // テキストバッファ int nMaxCount // コピーする最大文字数 );
「->」は、アロー演算子と呼ばれるものです。構造体へのポインタを参照する時は、「構造体->メンバ名」のように使います。
ソースコードの入力
ソースコードは下記のように入れてください。
#include <windows.h> #include <commctrl.h> #include "resource.h" #pragma comment(lib, "comctl32.lib") // グローバル変数: TCHAR szBuf_edit1[64], szBuf_edit2[64]; // このコード モジュールに含まれる関数の宣言を転送します: BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DialogProc1(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DialogProc2(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow ) { DialogBox(hInstance, TEXT("DIALOG_BOX"), NULL, DialogProc); return 0; } BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { UINT wmId; PROPSHEETPAGE psp; PROPSHEETHEADER psh; HPROPSHEETPAGE hPsp[2]; switch (msg) { case WM_INITDIALOG: InitCommonControls(); break; case WM_CLOSE: EndDialog(hWnd, IDOK); break; case WM_COMMAND: wmId = LOWORD(wParam); switch (wmId) { case IDM_EXIT: EndDialog(hWnd, IDOK); break; case IDM_PROP: psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_DEFAULT | PSP_USEICONID; psp.pszIcon = TEXT("IDI_TEST"); psp.hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); psp.pszTemplate = TEXT("DIALOG1"); psp.pfnDlgProc = (DLGPROC)DialogProc1; hPsp[0] = CreatePropertySheetPage(&psp); psp.pszTemplate = TEXT("DIALOG2"); psp.pfnDlgProc = (DLGPROC)DialogProc2; hPsp[1] = CreatePropertySheetPage(&psp); psh.dwSize = sizeof (PROPSHEETHEADER); psh.dwFlags = PSH_NOAPPLYNOW | PSH_USEHICON; psh.hwndParent = hWnd; psh.hIcon = LoadIcon(NULL, IDI_ASTERISK); psh.pszCaption = TEXT("設定"); psh.nPages = 2; psh.phpage = hPsp; PropertySheet(&psh); break; default: break; } default: break; } return FALSE; } BOOL CALLBACK DialogProc1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { NMHDR *nmhdr; switch(msg) { case WM_INITDIALOG: SetWindowText(GetDlgItem(hWnd, IDC_EDIT1), szBuf_edit1); break; case WM_NOTIFY: nmhdr = (NMHDR *)lParam; switch(nmhdr->code) { case PSN_APPLY: GetWindowText(GetDlgItem(hWnd, IDC_EDIT1), szBuf_edit1, sizeof(szBuf_edit1)); break; default: break; } break; } return FALSE; } BOOL CALLBACK DialogProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { NMHDR *nmhdr; switch(msg) { case WM_INITDIALOG: SetWindowText(GetDlgItem(hWnd, IDC_EDIT2), szBuf_edit2); break; case WM_NOTIFY: nmhdr = (NMHDR *)lParam; switch(nmhdr->code) { case PSN_APPLY: GetWindowText(GetDlgItem(hWnd, IDC_EDIT2), szBuf_edit2, sizeof(szBuf_edit2)); break; default: break; } break; } return FALSE; }
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDM_PROP 106
#define IDC_HP 109
#define IDC_EDIT1 1001
#define IDC_EDIT2 1002
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
Reseditで作成した場合は、これとは異なるソースコードになります。
上記の太線で示している箇所のみ追加です。
#include <windows.h> #include "resource.h" ///////////////////////////////////////////////////////////////////////////// // // アイコン // IDI_TEST ICON "test.ico" ///////////////////////////////////////////////////////////////////////////// // // メニュー // IDC_HP MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "アプリケーションの終了(&X)", IDM_EXIT MENUITEM "プロパティ(&P)", IDM_PROP END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // ダイアログ // DIALOG_BOX DIALOG 0, 0, 170, 62 FONT 9, "MS UI Gothic" CAPTION "ダイアログ" MENU IDC_HP BEGIN LTEXT "Copyright (C) 2008",IDC_STATIC,42,26,114,8 END DIALOG1 DIALOG 0, 0, 170, 62 FONT 9, "MS UI Gothic" CAPTION "設定1" BEGIN EDITTEXT IDC_EDIT1, 2, 2, 166, 13, ES_AUTOHSCROLL END DIALOG2 DIALOG 0, 0, 170, 62 FONT 9, "MS UI Gothic" CAPTION "設定2" BEGIN EDITTEXT IDC_EDIT2, 2, 2, 166, 13, ES_AUTOHSCROLL END
Reseditで作成した場合は、これとは異なるソースコードになります。
上記の太線で示している箇所のみ追加です。