第204章 アップダウンコントロール


アップダウンコントロールについてはまだやっていませんでした。 アップダウンコントロールというのは図を見れば一目瞭然だと思います。



メインウィンドウに直接エディットコントロールとアップダウンコントロールを 子供ウィンドウとして作ってみました。アップダウンコントロールを 操作してエディットコントロールの数値を上下するとメインウィンドウに その数値が表示されます。



アップダウンコントロールを作ってこれを制御するには、

1.コモンコントロールの前準備   INITCOMMONCONTROLSEX構造体のdwICCメンバはICC_UPDOWN_CLASS 2.CreateUpDownControl関数でコントロールを作る 3.WM_VSCROLL(WM_HSCROLL)メッセージの処理 4.必要に応じてUDN_DELTAPOSなどの処理

というような手順が必要です。

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 );

この関数が成功するとアップダウンコントロールのウィンドウハンドル を返し、失敗するとNULLが返されます。

dwStyleはアップダウンコントロールのウィンドウスタイルを指定します。 WS_CHILD, WS_BORDER, WS_VISIBLEを含んでいなくてはいけません。 その他にこのコントロールに特有なスタイルを含めることができます。
UDS_ALIGNLEFTアップダウンコントロールをバディウィンドウの 左に配置する
UDS_ALIGNRIGHTアップダウンコントロールをバディウィンドウの 右に配置する
UDS_ARROWKEYS上、下矢印キーで値を増減させる
UDS_AUTOBUDDYZオーダーが1つ奥のウィンドウをバディウィンドウに自動的に選択
UDS_HORZアップダウンコントロールの矢印が左右
UDS_NOTHOUSANDS3桁ごとに区切り記号を挿入しない
UDS_SETBUDDYINTアップダウンコントロールの位置が変化した時、バディウィンドウの テキストを設定する
これを設定するとWM_VSCROLL(WM_HSCROLL)を処理しなくてもよくなる
UDS_WRAP上限、下限を超えて増減された場合、値の位置を折り返す
x, y, cx, cyはコントロールの位置と幅、高さを指定します。
hParentは親のウィンドウハンドルを指定します。
nIDはアップダウンコントロールのIDを指定します。
hInstはインスタンスハンドルを指定します。
hBuddyには、バディウィンドウのハンドルを指定します。 これを指定するとx, y, cx, cyは無視されるようです。
nUpperには、範囲の上限を設定します。
nLowerには、範囲の下限を設定します。
nPosには、開始位置を指定します。

WM_VSCROLLメッセージはすでにいろいろなところで出てきましたが、 もう一度まとめると

WM_VSCROLL nScrollCode = (int) LOWORD(wParam); nPos = (short int) HIWORD(wParam); hwndScrollBar = (HWND) lParam;

ということになります。UDS_SETBUDDYINTスタイルを使用せずに 独自の表示形式を行いたい時にこのメッセージを処理します。

UDN_DELTAPOS lpnmud = (LPNMUPDOWN) lParam;

コントロールの位置が変えられようとする時に、システムから 親ウィンドウにこの通知メッセージが送られます。

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

typedef struct _NM_UPDOWN { NMHDR hdr; int iPos; int iDelta; } NMUPDOWN, FAR *LPNMUPDOWN;

以前はNM_UPDOWN構造体でしたが名前が 変更になました。
hdrはNMHDR構造体です。
iPosはアップダウンコントロールの現在位置を表す符号付整数です。
iDeltaは位置の変化を表す符号付整数です。

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

// 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; }

このへんはいつもと同じですが、コモンコントロールの準備を忘れないでください。

//ウィンドウプロシージャ 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_CREATEメッセージが来たらコモンコントロールを初期化して エディットコントロールとアップダウンコントロールを 作ります。この時インスタンスハンドルが必要になります。 GetWindowLong関数で取得してもよいのですが、ここではlpを利用しています。 (第19章を参照)

WM_VSCROLLの処理はアップダウンコントロールにUDS_SETBUDDYINT スタイルを設定すれば必要ないのですが、ここではエディットコントロールに 「%03d」形式で表示したいために処理をしています。

WM_PAINTメッセージが来たらクライアント領域に現在の コントロールの位置を表示させます。 今回はDrawText関数を使って表示しています。 (第5章参照)

WM_NOTIFTメッセージの処理に注意して下さい。
UDN_DELTAPOS通知メッセージが来た後のコントロールの値は iPos+iDeltaです。iPosは過去の値になってしまうことに注意して下さい。

また、クライアント領域の再描画はたいていの場合、領域全体に対して行っていましたが 今回はrc領域に限定しています。(ちらつきが少なくなる)

今回も特にめんどうなところはありませんでした。 上のプログラムではエディットコントロールを直接書き換えた場合 クライアント領域の表示には反映されません。これを反映されるように 書きなおして見て下さい。


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

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