左の図のようにトラックバーは縦型にしてみました。つまみを動かすと
「現在位置」のところに現在のつまみ位置がリアルタイムに表示されます。
「範囲選択開始」ボタンをおすと範囲の選択が開始されます。
つまみを動かした後、「範囲選択終了」ボタンを押すとそこが
選択範囲の終点となります。選択範囲もリアルタイムに表示されます。
ダイアログボックス上のトラックバーの操作は、親ウィンドウ
でもリアルタイムでモニタできます。
では、プログラムを見てみましょう。
ダイアログぽっくす上のトラックバーはリソースエディタで 作ります。VC++の人はトラックバーのプロパティを次のようにしてください。
「一般」ID=IDC_SLIDER1, 「可視」「タブストップ」にチェックをつけておきます。
「スタイル」方向=「垂直方向」, ポイント= 「下/右」, 「マークの設定」「選択可能」 「自動設定」にチェックをつけておきます。
「拡張スタイル」には特にチェックをつけません。
IDC_START, IDC_END, IDC_POSのスタティックコントロールに 範囲の開始位置、終了位置、現在の位置が表示されることになります。// track02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 102, 177 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "トラックバー" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "閉じる",IDOK,44,7,50,14 CONTROL "Slider1",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_ENABLESELRANGE | WS_TABSTOP,7,7,28,157 LTEXT "現在の位置:",IDC_STATIC,42,25,36,8 LTEXT "POS",IDC_POS,81,25,14,8 GROUPBOX "選択範囲",IDC_STATIC,46,40,49,57 LTEXT "終了",IDC_STATIC,49,76,15,8 LTEXT "",IDC_END,77,76,8,8 PUSHBUTTON "範囲選択開始",IDC_RANGESTART,44,105,50,14 PUSHBUTTON "範囲選択終了",IDC_RANGEEND,44,128,50,14 PUSHBUTTON "選択範囲クリア",IDC_CLEARSEL,44,151,50,14 LTEXT "開始",IDC_STATIC,49,57,15,8 LTEXT "",IDC_START,77,57,8,8 END ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "ダイアログ(&D)" BEGIN MENUITEM "トラックバー(&T)", IDM_TRACK END END
リソースエディタでトラックバーを 作る場合Comctl32.libのリンクは不要です。しかし、commctrl.hのインクルードは 必要です。// track02.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "track02"; //ウィンドウクラス HINSTANCE hInst; int iPosStart, iPosEnd, iPos;
親ウィンドウの初期状態の大きさは、表示が隠れない程度にしてあります。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; 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 = "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座標 210,//幅 115,//高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
WM_CREATEのところで一応コモンコントロールの初期化を しておきました。(リソースエディタで作った場合不要??)//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; INITCOMMONCONTROLSEX ic; char szStr[256]; HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_BAR_CLASSES; break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); wsprintf(szStr, "つまみ位置= %d", iPos); TextOut(hdc, 5, 5, szStr, lstrlen(szStr)); wsprintf(szStr, "選択範囲開始位置= %d", iPosStart); TextOut(hdc, 5, 25, szStr, lstrlen(szStr)); wsprintf(szStr, "選択範囲終了位置=%d", iPosEnd); TextOut(hdc, 5, 45, szStr, lstrlen(szStr)); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_TRACK: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
WM_PAINTメッセージが来たらクライアント領域に トラックバーの情報を表示します。
ダイアログボックスのプロシージャです。LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hTrack, hPos, hStart, hEnd, hRangeStart, hRangeEnd, hRangeClear; char szStr[16]; static HWND hParent; switch (msg) { case WM_INITDIALOG: hParent = GetParent(hDlg); hTrack = GetDlgItem(hDlg, IDC_SLIDER1); hPos = GetDlgItem(hDlg, IDC_POS); hStart = GetDlgItem(hDlg, IDC_START); hEnd = GetDlgItem(hDlg, IDC_END); hRangeStart = GetDlgItem(hDlg, IDC_RANGESTART); hRangeEnd = GetDlgItem(hDlg, IDC_RANGEEND); hRangeClear = GetDlgItem(hDlg, IDC_CLEARSEL); SendMessage(hTrack, TBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessage(hTrack, TBM_SETTICFREQ, (WPARAM)10, 0); iPos = SendMessage(hTrack, TBM_GETPOS, 0, 0); wsprintf(szStr, "%d", iPos); SetWindowText(hPos, szStr); SetWindowText(hStart, ""); SetWindowText(hEnd, ""); EnableWindow(hRangeEnd, FALSE); EnableWindow(hRangeClear, FALSE); SetFocus(hTrack); break; case WM_VSCROLL: iPos = SendMessage(hTrack, TBM_GETPOS, 0, 0); wsprintf(szStr, "%d", iPos); SetWindowText(hPos, szStr); InvalidateRect(hParent, NULL, TRUE); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: case IDCANCEL: EndDialog(hDlg, IDOK); return TRUE; case IDC_RANGESTART: iPosStart = SendMessage(hTrack, TBM_GETPOS, 0, 0); SendMessage(hTrack, TBM_SETSELSTART, (WPARAM)FALSE, (LPARAM)iPosStart); wsprintf(szStr, "%d", iPosStart); SetWindowText(hStart, szStr); EnableWindow(hRangeStart, FALSE); EnableWindow(hRangeEnd, TRUE); InvalidateRect(hParent, NULL, TRUE); SetFocus(hTrack); return TRUE; case IDC_RANGEEND: iPosEnd = SendMessage(hTrack, TBM_GETPOS, 0, 0); if (iPosStart > iPosEnd) { MessageBox(hDlg, "範囲終了位置は開始位置より下方にして下さい", "範囲設定エラー", MB_OK); return TRUE; } SendMessage(hTrack, TBM_SETSELEND, (WPARAM)TRUE, (LPARAM)iPosEnd); wsprintf(szStr, "%d", iPosEnd); SetWindowText(hEnd, szStr); EnableWindow(hRangeStart, TRUE); EnableWindow(hRangeEnd, FALSE); EnableWindow(hRangeClear, TRUE); InvalidateRect(hParent, NULL, TRUE); SetFocus(hTrack); return TRUE; case IDC_CLEARSEL: SendMessage(hTrack, TBM_CLEARSEL, (WPARAM)TRUE, 0); iPosStart = 0; iPosEnd = 0; EnableWindow(hRangeStart, TRUE); EnableWindow(hRangeEnd, FALSE); EnableWindow(hRangeClear, FALSE); SetWindowText(hStart, ""); SetWindowText(hEnd, ""); InvalidateRect(hParent, NULL, TRUE); SetFocus(hTrack); return TRUE; } return FALSE; } return FALSE; }
WM_INITDIALOGが来たらコントロール類の初期設定を行います。 コントロール類のウィンドウハンドルをスタティック変数に 取得しておくと後の作業が楽です。また、このプロシージャ内で 親ウィンドウのハンドルが必要なのでGetParent関数で最初に 取得しておきます。今回はトラックバーの最大、最小値を0から100までと して少し細かく設定できるようにしました。また、TBM_SETTICFREQメッセージは はメモリの頻度を指定します。
wFreqにメモリのインターバルを指定します。TBM_SETTICFREQ wParam = (WPARAM) wFreq; lParam = (LPARAM) 0;
このプログラムではダイアログボックスが 出るたびに前回の設定は無視されて、本当の初期状態になります。 余裕のある人は、前回の設定が反映されるように書き換えてみてください。
さて、縦型スクロールバーではつまみが動かされるとその親ウィンドウに WM_VSCROLLメッセージが届きます。この時wParamの下位ワード値 に通知メッセージが含まれます。通知メッセージが TB_THUMBTRACKとTB_THUMBPOSITIONの時はwParamの上位ワード値がつまみ位置を示します。 ここでは、WM_VSCROLLが来るたびにつまみ位置をTBM_GETPOSメッセージで グローバル変数iPosに取得して親のクライアント領域を再描画しています。
「範囲選択開始」「範囲選択終了」ボタンが押されるとその時の ボタン位置を取得して範囲を設定します。親ウィンドウを再描画して 情報を更新させます。終了位置が開始位置より大きい場合はエラーメッセージを 出すようにしてあります
「選択範囲クリア」ボタンが押されたらTBM_CLEARSELメッセージで 選択範囲をクリアします。
今回はごちゃごちゃしていて少し面倒くさいプログラムでしたが プログラム的には単純でした。
Update 05/Apr/1999 By Y.Kumei