メインウィンドウに直接エディットコントロールとアップダウンコントロールを
子供ウィンドウとして作ってみました。アップダウンコントロールを
操作してエディットコントロールの数値を上下するとメインウィンドウに
その数値が表示されます。
アップダウンコントロールを作ってこれを制御するには、
というような手順が必要です。1.コモンコントロールの前準備 INITCOMMONCONTROLSEX構造体のdwICCメンバはICC_UPDOWN_CLASS 2.CreateUpDownControl関数でコントロールを作る 3.WM_VSCROLL(WM_HSCROLL)メッセージの処理 4.必要に応じてUDN_DELTAPOSなどの処理
この関数が成功するとアップダウンコントロールのウィンドウハンドル を返し、失敗するとNULLが返されます。HWND CreateUpDownControl( DWORD dwStyle, int x, int y, int cx, int cy, HWND hParent, int nID, HINSTANCE hInst, HWND hBuddy, int nUpper, int nLower, int nPos );
dwStyleはアップダウンコントロールのウィンドウスタイルを指定します。 WS_CHILD, WS_BORDER, WS_VISIBLEを含んでいなくてはいけません。 その他にこのコントロールに特有なスタイルを含めることができます。
UDS_ALIGNLEFT | アップダウンコントロールをバディウィンドウの 左に配置する | |
UDS_ALIGNRIGHT | アップダウンコントロールをバディウィンドウの 右に配置する | |
UDS_ARROWKEYS | 上、下矢印キーで値を増減させる | |
UDS_AUTOBUDDY | Zオーダーが1つ奥のウィンドウをバディウィンドウに自動的に選択 | |
UDS_HORZ | アップダウンコントロールの矢印が左右 | |
UDS_NOTHOUSANDS | 3桁ごとに区切り記号を挿入しない | |
UDS_SETBUDDYINT | アップダウンコントロールの位置が変化した時、バディウィンドウの
テキストを設定する これを設定するとWM_VSCROLL(WM_HSCROLL)を処理しなくてもよくなる | |
UDS_WRAP | 上限、下限を超えて増減された場合、値の位置を折り返す |
WM_VSCROLLメッセージはすでにいろいろなところで出てきましたが、 もう一度まとめると
ということになります。UDS_SETBUDDYINTスタイルを使用せずに 独自の表示形式を行いたい時にこのメッセージを処理します。WM_VSCROLL nScrollCode = (int) LOWORD(wParam); nPos = (short int) HIWORD(wParam); hwndScrollBar = (HWND) lParam;
コントロールの位置が変えられようとする時に、システムから 親ウィンドウにこの通知メッセージが送られます。UDN_DELTAPOS lpnmud = (LPNMUPDOWN) lParam;
NMPUDOWN構造体は次のように定義されています。
以前はNM_UPDOWN構造体でしたが名前が 変更になました。typedef struct _NM_UPDOWN { NMHDR hdr; int iPos; int iDelta; } NMUPDOWN, FAR *LPNMUPDOWN;
では、プログラムを見てみましょう。
このへんはいつもと同じですが、コモンコントロールの準備を忘れないでください。// updwn01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #define ID_EDIT 100 #define ID_UPDOWN 101 #define UD_MIN 1 #define UD_MAX 100 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "updwn01"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 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 = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるUp-Down Control",//タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT,//X座標 CW_USEDEFAULT,//Y座標 110,//幅 90,//高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
WM_CREATEメッセージが来たらコモンコントロールを初期化して エディットコントロールとアップダウンコントロールを 作ります。この時インスタンスハンドルが必要になります。 GetWindowLong関数で取得してもよいのですが、ここではlpを利用しています。 (第19章を参照)//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HINSTANCE hInst; INITCOMMONCONTROLSEX ic; static HWND hEdit, hUpdown; static int nNo = 1; char str[64]; static RECT rc = {10, 45, 100, 70}; HDC hdc; PAINTSTRUCT ps; char szStr[256]; LPNMUPDOWN lpnmud; switch (msg) { case WM_CREATE: hInst = ((CREATESTRUCT *)lp)->hInstance; ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_UPDOWN_CLASS; InitCommonControlsEx(&ic); hEdit = CreateWindowEx(0, "Edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 70, 30, hWnd, (HMENU)ID_EDIT, hInst, NULL); hUpdown = CreateUpDownControl( WS_CHILD | WS_VISIBLE | WS_BORDER | UDS_ALIGNRIGHT,//ウィンドウスタイル 0, 0, 0, 0,//位置、大きさ hWnd,//親ウィンドウ ID_UPDOWN,//コントロールのID hInst,//インスタンスハンドル hEdit,//関連付けられているバディウィンドウ UD_MAX,//範囲の上限 UD_MIN,//範囲の下限 1);//開始位置 SetWindowText(hEdit, "001"); break; case WM_VSCROLL: if ((HWND)lp == hUpdown) { wsprintf(str, "%03d", HIWORD(wp)); SetWindowText(hEdit, str); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); wsprintf(szStr, "現在%03dです", nNo); DrawText(hdc, szStr, -1, &rc, DT_LEFT); EndPaint(hWnd, &ps); break; case WM_NOTIFY: if (wp == (WPARAM)ID_UPDOWN) { lpnmud = (LPNMUPDOWN)lp; if(lpnmud->hdr.code == UDN_DELTAPOS) { nNo = lpnmud->iPos + lpnmud->iDelta; if (nNo < UD_MIN) nNo = UD_MIN; if (nNo > UD_MAX) nNo = UD_MAX; InvalidateRect(hWnd, &rc, TRUE); } } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hEdit); DestroyWindow(hUpdown); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
WM_VSCROLLの処理はアップダウンコントロールにUDS_SETBUDDYINT スタイルを設定すれば必要ないのですが、ここではエディットコントロールに 「%03d」形式で表示したいために処理をしています。
WM_PAINTメッセージが来たらクライアント領域に現在の コントロールの位置を表示させます。 今回はDrawText関数を使って表示しています。 (第5章参照)
WM_NOTIFTメッセージの処理に注意して下さい。
UDN_DELTAPOS通知メッセージが来た後のコントロールの値は
iPos+iDeltaです。iPosは過去の値になってしまうことに注意して下さい。
また、クライアント領域の再描画はたいていの場合、領域全体に対して行っていましたが 今回はrc領域に限定しています。(ちらつきが少なくなる)
今回も特にめんどうなところはありませんでした。 上のプログラムではエディットコントロールを直接書き換えた場合 クライアント領域の表示には反映されません。これを反映されるように 書きなおして見て下さい。
Update 24/May/1999 By Y.Kumei