第210章 フラットスクロールバーの水平スクロール


今回は前章で作ったプログラムに水平スクロールバーを付けます。 簡単そうに思えますが、ちょっと間違えるとなかなかバグがわかりません。



水平スクロールバーが付きました。



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

リソース・スクリプトは前回と全く同じなので省略します。

// fltscb02.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #include "resource.h" #define LINESIZE 20 //1行の高さ #define MAXLINE 10 //行数 #define CHARWIDTH 8 //1文字の幅 #define CHARNUMBER 38//一行の文字数 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "fltscb02"; //ウィンドウクラス

ここでは、簡単のために1文字の横幅をdefineしています。 実際にはGetTextMetrics関数 (第77章)を使ってTEXTMETRIC構造体の tmAveCharWidthメンバを調べます。

コモンコントロールの準備を忘れないでください。

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; } //ウィンドウ・クラスの登録 BOOL 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, "猫でもわかるFlat Scroll Bar",//タイトルバーにこの名前が表示されます 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, i, len, dx, dy; HDC hdc; PAINTSTRUCT ps; char *str_org = "%2d: 第%2d行目 猫でもわかるスクロールバー"; char str[256]; static SCROLLINFO si, sih; static int dispno, pos, dispnoh, posh; static int nStyle; //0:Flat 1:Encarta 2:Old static HMENU hMenu; switch (msg) { case WM_CREATE: InitializeFlatSB(hWnd); FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_FLAT_MODE, TRUE); FlatSB_SetScrollProp(hWnd, WSB_PROP_HSTYLE, FSB_FLAT_MODE, TRUE); hMenu = GetMenu(hWnd); break; case WM_INITMENU: switch (nStyle) { case 0: EnableMenuItem(hMenu, IDM_FLAT, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_ENCARTA, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, IDM_OLD, MF_BYCOMMAND | MF_ENABLED); break; case 1: EnableMenuItem(hMenu, IDM_ENCARTA, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_FLAT, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, IDM_OLD, MF_BYCOMMAND | MF_ENABLED); break; case 2: EnableMenuItem(hMenu, IDM_OLD, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_FLAT, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, IDM_ENCARTA, MF_BYCOMMAND | MF_ENABLED); break; } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_OLD: FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_REGULAR_MODE, TRUE); FlatSB_SetScrollProp(hWnd, WSB_PROP_HSTYLE, FSB_REGULAR_MODE, TRUE); nStyle = 2; break; case IDM_FLAT: FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_FLAT_MODE, TRUE); FlatSB_SetScrollProp(hWnd, WSB_PROP_HSTYLE, FSB_FLAT_MODE, TRUE); nStyle = 0; break; case IDM_ENCARTA: FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_ENCARTA_MODE, TRUE); FlatSB_SetScrollProp(hWnd, WSB_PROP_HSTYLE, FSB_ENCARTA_MODE, TRUE); nStyle = 1; break; } break; case WM_SIZE: dispno = HIWORD(lp) / LINESIZE; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = MAXLINE; si.nPage = dispno; si.nPos = pos; FlatSB_SetScrollInfo(hWnd, SB_VERT, &si, TRUE); dispnoh = LOWORD(lp) / CHARWIDTH; sih.cbSize = sizeof(SCROLLINFO); sih.fMask = SIF_ALL; sih.nMin = 0; sih.nMax = CHARNUMBER; sih.nPage = dispnoh; sih.nPos = posh; FlatSB_SetScrollInfo(hWnd, SB_HORZ, &sih, TRUE); break; case WM_VSCROLL: switch (LOWORD(wp)) { case SB_LINEUP: dy = -1; break; case SB_LINEDOWN: dy = 1; break; case SB_PAGEUP: dy = -1 * si.nPage; break; case SB_PAGEDOWN: dy = si.nPage; break; case SB_THUMBTRACK: dy = HIWORD(wp) - si.nPos; break; default: dy = 0; break; } dy = max(-1 * si.nPos, min(dy, si.nMax - si.nPos)); if (dy != 0) { si.nPos += dy; pos = si.nPos; FlatSB_SetScrollInfo(hWnd, SB_VERT, &si, TRUE); ScrollWindowEx(hWnd, 0, -dy * LINESIZE, NULL, NULL, NULL, NULL, 0); InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hWnd); } break; case WM_HSCROLL: switch (LOWORD(wp)) { case SB_LINEUP: dx = -1; break; case SB_LINEDOWN: dx = 1; break; case SB_PAGEUP: dx = -1 * sih.nPage; break; case SB_PAGEDOWN: dx = sih.nPage; break; case SB_THUMBTRACK: dx = HIWORD(wp) - sih.nPos; break; default: dx = 0; break; } dx = max(-1 * sih.nPos, min(dx, sih.nMax - sih.nPos)); if (dx != 0) { sih.nPos += dx; posh = sih.nPos; FlatSB_SetScrollInfo(hWnd, SB_HORZ, &sih, TRUE); ScrollWindowEx(hWnd, -dx * CHARWIDTH, 0, NULL, NULL, NULL, NULL, 0); InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hWnd); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); for (i = 0 ;i <= dispno; i++) { if (i + si.nPos <= MAXLINE) { len = wsprintf(str, str_org, i+si.nPos, i+si.nPos); TextOut(hdc, 10 - sih.nPos * CHARWIDTH, i * LINESIZE, str, len); } } EndPaint(hWnd, &ps); 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; }

ちょっと長いですが、ひとつずつ見ていくとたいした事はありません。

水平スクロールようにdx, sih, dispnoh, poshの各変数を用意しました。

WM_CREATEメッセージが来たら、フラットスクロールバーを初期化して 各プロパティを設定します。

WM_INITMENUの処理は同じです。

メニューから「オプション」を選択してスクロールバーの外観を 変えるところは、水平スクロールバーについてもFlatSB_SetScrollProp関数を 実行するのを忘れないでください。

WM_SIZEメッセージの処理は重要です。
水平スクロールバーの処理ではページ幅をクライアント領域の 横幅を文字幅で割った数に設定します。要するに現在見えている 1行分の文字数がページ幅になります。

WH_HSCROLLの処理も簡単そうですが、混乱をきたしやすいです。 このプログラムではdxは水平方向に 何文字移動するかです。(ピクセルと勘違いしやすい)

WM_PAINTの処理は簡単です。 TextOut関数の第2引数を10-sih.nPos*CHARWIDTHにすればよいだけです。

こう書くと簡単ですね。スクロールバーの処理はこれ以外にもいろいろな 方法があります。研究してみてください。


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

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