第209章 フラットスクロールバー


今回は、フラットスクロールバーについてやります。 作り方は従来のスクロールバーとたいして変わりません。 これが扱えるのは、Comctl32.dllのバージョンが4.71以降です。



左の図を見て下さい。スクロールバーがフラットになっています。 また、下方のアローつまみの色が濃くなって強調表示 されています。ここに、マウスがポイントされているからです。

この外にENCARTAスタイルといって、マウスがポイントされると 従来のスクロールバーのように立体表示になるものもあります。

今回はメニューの「オプション」からスクロールバーの外観 を変えられるようにしてみました。
では、必要な手続きを見てみましょう。

1.commctrl.hをインクルードします 2.Comctl32.libをリンクします。

ま、一般のコモンコントロールと同じ手順です。

BOOL InitializeFlatSB( HWND hwnd );

フラットスクロールバーを初期化します。
hwndにはフラットスクロールバーを持つウィンドウのハンドルを指定します。

BOOL FlatSB_SetScrollProp( HWND hwnd, UINT index, int newValue, BOOL fRedraw );

フラットスクロールバーのプロパティをセットします。

hwndはフラットスクロールバーを持つウィンドウのハンドルです。
indexは次の中から1つを選びます。
WSB_PROP_CXHSCROLL newValueは、水平スクロールバーの 方向ボタンの幅(ピクセル単位)のINT値です。
WSB_PROP_CXHTHUMB newValueは、水平スクロールバーの スクロールつまみの幅(ピクセル単位)のINT値です。
WSB_PROP_CXVSCROLL newValueは、垂直スクロールバーの 幅(ピクセル単位)のINT値です。
WSB_PROP_CYHSCROLL newValueは、水平スクロールバーの 高さ(ピクセル単位)のINT値です。
WSB_PROP_CYVSCROLL newValueは垂直スクロールバーの方向ボタンの高さ(ピクセル単位)のINT値です。
WSB_PROP_CYVTHUMBnewValueは、垂直スクロールバーのスクロールつまみの高さ(ピクセル単位)のINT値です。
WSB_PROP_HBKGCOLOR newValurは水平スクロールバーの背景色を表すCOLORREF値です。
WSB_PROP_HSTYLE newValueは次の値の1つです。水平スクロールバーの外観を変えます。FSB_ENCARTA_MODE, FSB_FLAT_MODE, FSB_REGULAR_MODE
WSB_PROP_PALETTE newValueはスクロールバーが描画される時に使われるHPALETTE値です。
WSB_PROP_VBKGCOLORnewValurは垂直スクロールバーの背景色を表すCOLORREF値です。
WSB_PROP_VSTYLE newValueの値によって垂直スクロールバーの外観を変えます。FSB_ENCARTA_MODE, FSB_FLAT_MODE, FSB_REGULAR_MODE
newValueは前項の説明を見て下さい。
fRedrawは直ちにスクロールバーを再描画するかどうかの バラメーターです。TRUEなら直ちに再描画します。

int FlatSB_SetScrollInfo( HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw );

hwndは、フラットスクロールバーを含むウィンドウのハンドルです。
fnBarは、スクロールバーのタイプを指定します。 SB_HORZ(水平スクロールバー), SB_VERT(垂直スクロールバー)のいずれかを指定します。
lpsiは、SCROLLINFO構造体のアドレスを指定します。(第100章参照) fRedrawは、スクロールバーを直ちに再描画するかどうかを指定します。TRUEならば直ちに 再描画します。

int ScrollWindowEx( HWND hWnd, int dx, int dy, CONST RECT *prcScroll, CONST RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, UINT flags );

この関数はクライアント領域の内容をスクロールします。 以前ScrollWindow関数が使われていましたが、これにとって変わられました。

hWndには、ウィンドウハンドルを指定します。
dxには、水平方向のスクロール量をデバイス単位で指定します。
dyには、垂直方向のスクロール量を指定します。
prcScrollには、スクロール対象とするRECT構造体へのポインタを指定します。 NULLを指定するとクライアント領域全体がスクロールします。
prcClipには、クリッピング領域の座標が入ったRECT構造体へのポインタを指定します。
hrgnUpdateには、リージョンハンドルを指定します。スクロールによって無効化された領域が 格納されます。この情報が不要な時はNULLを指定します。
prcUpdateには、RECT構造体へのポインタを指定します。これに、スクロールによって 無効化された長方形が格納されます。この情報が不要な時はNULLを指定します。
flagsにはスクロールを制御するフラグを指定します。
SW_ERASEスクロール後無効化されたリージョンを消去します。次の SW_INVALIDATEと同時に指定します。
SW_INVALIDATEスクロール後hrgnUpdateを無効化します。
SW_SCROLLCHILDRENprcScrollと重なるすべての子ウィンドウもスクロールします。

さて、これだけでフラットスクロールバーつきのウィンドウを作ることができます。

// fltscb01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "従来スタイル(&C)", IDM_OLD MENUITEM "ENCARTAスタイル(&E)", IDM_ENCARTA MENUITEM "FLATスタイル(&F)", IDM_FLAT END END

ごく普通のメニューのリソース・スクリプトです。

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

commctrl.hをインクルードしたりcomctl32.libをリンクするのを 忘れないでください。

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

これは、いつもと同じです。ウィンドウスタイルにWS_VSCROLL などを加えないでください。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, i, len, dy; HDC hdc; PAINTSTRUCT ps; char *str_org = "%2d: 第%2d行目 猫でもわかるスクロールバー"; char str[256]; static SCROLLINFO si; static int dispno, pos; 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); 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); nStyle = 2; break; case IDM_FLAT: FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_FLAT_MODE, TRUE); nStyle = 0; break; case IDM_ENCARTA: FlatSB_SetScrollProp(hWnd, WSB_PROP_VSTYLE, FSB_ENCARTA_MODE, TRUE); nStyle = 1; break; } break; case WM_SIZE: dispno = HIWORD(lp) / LINESIZE; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = MAXLINE; si.nPage = dispno; si.nPos = pos; FlatSB_SetScrollInfo(hWnd, SB_VERT, &si, 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_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, 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; }

nStyleには現在のスクロールバーのスタイルを保存しておきます。

WM_CREATEが来たらフラットスクロールバーを初期化して、初期状態の スクロールバーのプロパティを設定しておきます。 また、メニューハンドルを取得して保存しておきます。

WM_INITMENUメッセージが来たらnStyleの値に応じて メニュー項目の選択可否を設定しておきます。 なお、WM_INITMENUについては第160章 を参照して下さい。

メニューで「オプション」からスクロールバーのプロパティの 変更の命令が来たら、FlatSB_SetScrollProp関数で外観を変えます。

WM_SIZE, WM_VSCROLL, WM_PAINTメッセージが来た時の処理は 第100章とほぼ同じです。

今回は水平方向のスクロールについては考慮していません。 水平方向にもフラットスクロールバーをつけてみて下さい。


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

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