スクロールバーコントロール

スクロールバーコントロールはウィンドウのスクロールバーによく似ています。
ウィンドウのスクロールバーはクライアント領域のスクロールに使用しますが、コントロールとしてのスクロールバーはウィンドウ上の任意の場所に設置でき、その値も自由に使用することができます。

スクロールバーコントロールの作成

スクロールバーコントロールはSCROLLBARクラスで作成できます。


#define IDC_SCROLLBAR1 100

case WM_CREATE:
	CreateWindow(
		L"SCROLLBAR", NULL,
		WS_CHILD | WS_VISIBLE | SBS_HORZ,
		10, 10, 200, 18,
		hWnd, (HMENU)IDC_SCROLLBAR1, hInst, NULL);

ウィンドウスタイルにSBS_HORZを指定すると水平、SBS_VERTを指定すると垂直のスクロールバーコントロールを作成できます。
スクロールバーコントロールの作成

ただし作成しただけでは操作しても何も起こりませんし、バーを動かすことすらできません。
ウィンドウのスクロールバーの時と同じく、動作は自分で定義する必要があります。
使用するメッセージと関数は同じなので、スクロールバーも参考にしてください。

スクロールバーコントロールを操作すると、親ウィンドウにWM_HSCROLL(水平)またはWM_VSCROLL(垂直)が送られてきます。
このときLPARAMには操作したコントロールのハンドルが格納されています。
(ウィンドウのスクロールバーの場合はLPARAMはNULLです)
SetScrollInfo関数(GetScrollInfo関数)の第二引数にはコントロールのスクロールバーであることを示す定数SB_CTLを指定します。

後の処理はウィンドウのスクロールバーと同じです。


#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define IDC_SCROLLH 100
#define IDC_SCROLLV 101
#define BUFFERSIZE 8

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hScrollH, hScrollV;
	static WCHAR txtH[BUFFERSIZE];
	static WCHAR txtV[BUFFERSIZE];

	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;
	SCROLLINFO si;

	switch (message)
	{
	case WM_CREATE: //ウィンドウ作成
		//水平スクロールバーコントロール
		hScrollH = CreateWindow(
			L"SCROLLBAR", NULL,
			WS_CHILD | WS_VISIBLE | SBS_HORZ,
			30, 10, 100, 15,
			hWnd, (HMENU)IDC_SCROLLH, hInst, NULL);
		//垂直スクロールバーコントロール
		hScrollV = CreateWindow(
			L"SCROLLBAR", NULL,
			WS_CHILD | WS_VISIBLE | SBS_VERT,
			10, 30, 15, 100,
			hWnd, (HMENU)IDC_SCROLLV, hInst, NULL);

		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nPage = 10;
		si.nMin = 0;
		//スクロール可能な範囲はnMaxで指定した値よりも
		//「ページサイズ - 1」分だけ少なくなるので
		//その分だけ加算しておく
		si.nMax = 100 + (si.nPage - 1);
		
		SetScrollInfo(hScrollH, SB_CTL, &si, TRUE);
		SetScrollInfo(hScrollV, SB_CTL, &si, TRUE);

		StringCchPrintf(txtH, BUFFERSIZE, L"0");
		StringCchPrintf(txtV, BUFFERSIZE, L"0");
		break;

	case WM_HSCROLL: //水平スクロール
		if (lParam != hScrollH)
			break;

		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_ALL;
		GetScrollInfo(hScrollH, SB_CTL, &si);

		switch (LOWORD(wParam)) {
		case SB_LEFT:
			si.nPos = si.nMin;
			break;
		case SB_RIGHT:
			si.nPos = si.nMax - (si.nPage - 1);
			break;
		case SB_LINELEFT:
			if(si.nPos > 0)
				si.nPos -= 1;
			break;
		case SB_LINERIGHT:
			if (si.nPos < si.nMax - (si.nPage - 1))
				si.nPos += 1;
			break;
		case SB_PAGELEFT:
			si.nPos -= si.nPage;
			break;
		case SB_PAGERIGHT:
			si.nPos += si.nPage;
			break;
		case SB_THUMBTRACK:
			si.nPos = HIWORD(wParam);
			break;
		case SB_THUMBPOSITION:
			si.nPos = HIWORD(wParam);
			break;
		}
		SetScrollInfo(hScrollH, SB_CTL, &si, TRUE);

		StringCchPrintf(txtH, BUFFERSIZE, L"%d", si.nPos);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_VSCROLL: //垂直スクロール
		if (lParam != hScrollV)
			break;

		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_ALL;
		GetScrollInfo(hScrollV, SB_CTL, &si);

		switch (LOWORD(wParam)) {
		case SB_TOP:
			si.nPos = si.nMin;
			break;
		case SB_BOTTOM:
			si.nPos = si.nMax - (si.nPage - 1);
			break;
		case SB_LINEUP:
			if (si.nPos > 0)
				si.nPos -= 1;
			break;
		case SB_LINEDOWN:
			if (si.nPos < si.nMax - (si.nPage - 1))
				si.nPos += 1;
			break;
		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;
		case SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;
		case SB_THUMBTRACK:
			si.nPos = HIWORD(wParam);
			break;
		case SB_THUMBPOSITION:
			si.nPos = HIWORD(wParam);
			break;
		}
		SetScrollInfo(hScrollV, SB_CTL, &si, TRUE);

		StringCchPrintf(txtV, BUFFERSIZE, L"%d", si.nPos);
		InvalidateRect(hWnd, NULL, TRUE);
		break;	

	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);

		TextOut(hdc, 135, 10, txtH, lstrlen(txtH));
		TextOut(hdc, 10, 135, txtV, lstrlen(txtV));

		EndPaint(hWnd, &ps);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

水平スクロールバーと垂直スクロールバーを作成し、それぞれの値を文字列で表示しています。

コード中にもコメントで書いていますが、スクロールバーのスクロール可能な範囲はnMinからnMaxまでではありません。
nPage - 1、つまり「スクロールボックスのサイズ - 1」分だけ実際にスクロール可能な範囲は小さくなります。

スクロールバーコントロールのスタイル

スクロールバーコントロールには以下のスタイルが指定できます。

定数 説明
SBS_HORZ 水平スクロールバー
スクロールバーのサイズはCreateWindow関数で指定した通りのサイズになる
SBS_VERT 垂直スクロールバー
スクロールバーのサイズはCreateWindow関数で指定した通りのサイズになる
SBS_TOPALIGN スクロールバーの上端を、CreateWindow関数で指定した矩形領域の上端に合わせる
高さは既定の高さになる
このスタイルはSBS_HORZスタイルと共に使用する
SBS_LEFTALIGN スクロールバーの左端を、CreateWindow関数で指定した矩形領域の左端に合わせる
幅は既定の幅になる
このスタイルはSBS_VERTスタイルと共に使用する
SBS_BOTTOMALIGN スクロールバーの下端を、CreateWindow関数で指定した矩形領域の下端に合わせる
高さは既定の高さになる
このスタイルはSBS_HORZスタイルと共に使用する
SBS_RIGHTALIGN スクロールバーの右端を、CreateWindow関数で指定した矩形領域の右端に合わせる
幅は既定の幅になる
このスタイルはSBS_VERTスタイルと共に使用する
SBS_SIZEBOX サイズボックス
(ウィンドウサイズを変更するコントロール)
サイズはCreateWindow関数で指定した通りのサイズになる
SBS_SIZEBOXTOPLEFTALIGN サイズボックスの左上隅を、CreateWindow関数で指定した矩形領域の左上隅に合わせる
サイズは既定のサイズになる
このスタイルはSBS_SIZEBOXまたはSBS_SIZEGRIPスタイルと共に使用する
SBS_SIZEBOXBOTTOMRIGHTALIGN サイズボックスの右上隅を、CreateWindow関数で指定した矩形領域の右上隅に合わせる
サイズは既定のサイズになる
このスタイルはSBS_SIZEBOXまたはSBS_SIZEGRIPスタイルと共に使用する
SBS_SIZEGRIP サイズボックス
SBS_SIZEBOXと同じだがグリップのあるデザインになっている