チェックボックス

チェックボックスの作成

チェックボックスコントロールはオン/オフの状態を持つボタンです。

ボタンなのでBUTTONクラスで作成します。
ウィンドウスタイルにBS_CHECKBOXを指定するとチェックボックスを作成できます。

コントロールの作成の基本的なことはボタンコントロールの項を参照してください。

ウィンドウスタイルにボタンの種類を指定しない場合、BS_PUSHBUTTONが指定されたものと解釈されます。
これは通常のプッシュボタンを作成します。


#define IDC_CHECK1 100

//チェックボックスの作成
CreateWindow(
	L"BUTTON", L"Check",
	WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
	10, 10, 80, 25,
	hWnd, (HMENU)IDC_CHECK1, hInst, NULL);

チェックボックスの作成

これでチェックボックスが作成できます。
プッシュボタンの時と同様に、クリックするとWM_COMMANDメッセージが通知されます。
しかしこの状態ではクリックしてもチェックのオン/オフは変わりません。

チェック状態の操作

BS_AUTOCHECKBOXスタイル

クリックするごとにチェックの状態を切り替えるにはBS_AUTOCHECKBOXスタイルを使用します。


//チェックボックスの作成
CreateWindow(
	L"BUTTON", L"Check",
	WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
	10, 10, 80, 25,
	hWnd, (HMENU)IDC_CHECK1, hInst, NULL);

チェックボックスはクリックごとにオン/オフを切り替えることが多いと思うので、通常はこれを使用するのが良いでしょう。

BM_SETCHECKメッセージ

チェックボックスのオン/オフの状態はBM_SETCHECKメッセージで設定できます。
これはSendMessage関数で送信します。

SendMessage関数のWPARAMには、設定したい状態の定数を指定します。
BST_CHECKEDを指定するとチェックをオンにします。
BST_UNCHECKEDを指定するとチェックをオフにします。
LPARAMは使用しないのでNULL(または0)を指定します。
戻り値は常に0です。

このメッセージによってチェックボックスの状態を変更してもWM_COMMANDメッセージは送信されません。

BM_GETCHECKメッセージ

チェックボックスのオン/オフの状態はBM_GETCHECKメッセージで取得できます。

SendMessage関数のWPARAMLPARAMは共に使用しないのでNULL(または0)を指定します。
オンの状態ならBST_CHECKEDを返します。
オフの状態はらBST_UNCHECKEDを返します。

BM_SETCHECK/BM_GETCHECメッセージを使用したチェックボックスのサンプルです。


#include <windows.h>

BOOL HasUnChecked(HWND[], size_t);
void OnClickCheckBox(HWND, HWND[], size_t);

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

#define IDC_CHECK1 100
#define IDC_CHECK2 101
#define IDC_CHECK3 102
#define IDC_BUTTON1 103

#define CHECKBOX_NUM 3

//チェックボックスにひとつでもオフ状態があればTRUEを返す
BOOL HasUnChecked(HWND hCheckBoxes[], size_t length)
{
	for (size_t i = 0; i < length; i++)
	{
		if (SendMessage(hCheckBoxes[i], BM_GETCHECK, 0, 0) == BST_UNCHECKED) {
			return TRUE;
		}
	}
	return FALSE;
}

//チェックボックスのクリック時にボタンテキストを切り替える
void OnClickCheckBox(HWND hBtn, HWND hCheckBoxes[], size_t length)
{
	SendMessage(
		hBtn,
		WM_SETTEXT,
		0, 
		(LPARAM)(HasUnChecked(hCheckBoxes, length) ? L"All On" : L"All Off"));
}

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hCheckBoxes[CHECKBOX_NUM];
	static HWND hBtn;

	switch (message)
	{
	case WM_CREATE: //ウィンドウ作成
		hCheckBoxes[0] = CreateWindow(
			L"BUTTON", L"Check1",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			10, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK1, hInst, NULL);
		hCheckBoxes[1] = CreateWindow(
			L"BUTTON", L"Check2",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			90, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK2, hInst, NULL);
		hCheckBoxes[2] = CreateWindow(
			L"BUTTON", L"Check3",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			170, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK3, hInst, NULL);

		hBtn = CreateWindow(
			L"BUTTON", L"All On",
			WS_CHILD | WS_VISIBLE,
			10, 45, 80, 25,
			hWnd, (HMENU)IDC_BUTTON1, hInst, NULL);
		break;

	case WM_COMMAND: //コントロールの操作
		switch (LOWORD(wParam))
		{
		case IDC_CHECK1:
		case IDC_CHECK2:
		case IDC_CHECK3:
			OnClickCheckBox(hBtn, hCheckBoxes, CHECKBOX_NUM);
			break;
		case IDC_BUTTON1:
			if (HasUnChecked(hCheckBoxes, CHECKBOX_NUM)) {
				for (int i = 0; i < CHECKBOX_NUM; i++) {
					SendMessage(hCheckBoxes[i], BM_SETCHECK, BST_CHECKED, 0);
				}
				SendMessage(hBtn, WM_SETTEXT, 0, (LPARAM)L"All Off");
			}
			else {
				for (int i = 0; i < CHECKBOX_NUM; i++) {
					SendMessage(hCheckBoxes[i], BM_SETCHECK, BST_UNCHECKED, 0);
				}
				SendMessage(hBtn, WM_SETTEXT, 0, (LPARAM)L"All On");
			}
			break;
		}
		break;

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

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

実行結果です。
チェックボックスの状態の取得と変更

このチェックボックスは個別に操作可能なほか、下のボタンを押すとすべてのチェックボックスを一括でオン/オフが出来ます。
ボタンのテキストはチェックボックスの状態によって切り替わります。

3状態チェックボックス

チェックボックスは「オン」「オフ」のふたつの状態を表しますが、オンでもオフでもない第三の状態を持てる3状態チェックボックスを作ることもできます。

3状態チェックボックスはウィンドウスタイルにBS_3STATEを指定して作成します。
このスタイルではBS_CHECKBOXスタイルと同様、クリックしても状態が切り替わりません。
クリックするごとに状態が切り替わる3状態チェックボックスはBS_AUTO3STATEで作成できます。

3状態チェックボックスの「オン」と「オフ」については2状態チェックボックスと同じです。
(BST_CHECKEDBST_UNCHECKED)
3つ目の状態は定数BST_INDETERMINATEで表され、「どちらでもない」「あいまい」な状態を意味します。

3つ目の状態をどのように扱うかはプログラマ次第です。
例えばいくつかのチェックボックスの状態を一括して表す場合に、オンとオフの状態が混在している場合に「どちらでもない」状態を使用できます。


#include <windows.h>

short GetCheckboxesState(HWND[], size_t);
void OnClickCheckBox(HWND, HWND[], size_t);

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

#define IDC_CHECK1 100
#define IDC_CHECK2 101
#define IDC_CHECK3 102
#define IDC_CHECKALL 103

#define CHECKBOX_NUM 3

//複数のチェックボックスの状態を返す
short GetCheckboxesState(HWND hCheckBoxes[], size_t length)
{	
	int count = 0;
	for (size_t i = 0; i < length; i++)
	{
		if (SendMessage(hCheckBoxes[i], BM_GETCHECK, 0, 0) == BST_CHECKED) {
			count++;
		}
	}
	return count == 0 ?
		BST_UNCHECKED : count == length ?
		BST_CHECKED : BST_INDETERMINATE;
}

//チェックボックスのクリック時にボタンの状態とテキストを切り替える
void OnClickCheckBox(HWND hBtn, HWND hCheckBoxes[], size_t length)
{
	short state = GetCheckboxesState(hCheckBoxes, length);
	SendMessage(hBtn, BM_SETCHECK, state, 0);
	SendMessage(hBtn, WM_SETTEXT, 0,
		state == BST_CHECKED ? L"All Off" : L"All On");
}

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hCheckBoxes[CHECKBOX_NUM];
	static HWND hCheck3State;

	short state;

	switch (message)
	{
	case WM_CREATE: //ウィンドウ作成
		hCheckBoxes[0] = CreateWindow(
			L"BUTTON", L"Check1",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			10, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK1, hInst, NULL);
		hCheckBoxes[1] = CreateWindow(
			L"BUTTON", L"Check2",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			90, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK2, hInst, NULL);
		hCheckBoxes[2] = CreateWindow(
			L"BUTTON", L"Check3",
			WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			170, 10, 80, 25,
			hWnd, (HMENU)IDC_CHECK3, hInst, NULL);

		hCheck3State = CreateWindow(
			L"BUTTON", L"All On",
			WS_CHILD | WS_VISIBLE | BS_3STATE,
			10, 45, 80, 25,
			hWnd, (HMENU)IDC_CHECKALL, hInst, NULL);
		break;
		
	case WM_COMMAND: //コントロールの操作
		switch (LOWORD(wParam))
		{
		case IDC_CHECK1:
		case IDC_CHECK2:
		case IDC_CHECK3:
			OnClickCheckBox(hCheck3State, hCheckBoxes, CHECKBOX_NUM);
			break;
		case IDC_CHECKALL:
			//手動でチェックボックスの状態を切り替える
			state = SendMessage(hCheck3State, BM_GETCHECK, 0, 0);
			state = state == BST_CHECKED ? BST_UNCHECKED : BST_CHECKED;
			SendMessage(hCheck3State, BM_SETCHECK, (WPARAM)state, 0);

			if (state == BST_UNCHECKED) {
				for (int i = 0; i < CHECKBOX_NUM; i++) {
					SendMessage(hCheckBoxes[i], BM_SETCHECK, BST_UNCHECKED, 0);
				}
				SendMessage(hCheck3State, WM_SETTEXT, 0, (LPARAM)L"All On");
			}
			else {//BST_CHECKED or BST_INDETERMINATE
				for (int i = 0; i < CHECKBOX_NUM; i++) {
					SendMessage(hCheckBoxes[i], BM_SETCHECK, BST_CHECKED, 0);
				}
				SendMessage(hCheck3State, WM_SETTEXT, 0, (LPARAM)L"All Off");
			}
			break;
		}
		break;

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

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

実行結果です。
上段のチェックボックスを1つまたは2つチェックが入った状態にすると、下段のチェックボックスが「あいまい」な状態になります。
3状態チェックボックス

テキストの位置

チェックボックスは「左にボックス、右にテキスト」という形で作成されますが、BS_LEFTTEXTスタイルまたはBS_RIGHTBUTTONスタイルを使用することで、左右を入れ替えることができます。


CreateWindow(
	L"BUTTON", L"Check1",
	WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
	10, 10, 80, 25,
	hWnd, (HMENU)IDC_CHECK1, hInst, NULL);

//ボックスの位置の左右入れ替え
CreateWindow(
	L"BUTTON", L"Check2",
	WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT,
	10, 40, 80, 25,
	hWnd, (HMENU)IDC_CHECK2, hInst, NULL);

ボックス位置の左右入れ替え

テキストの左揃え/右揃えはBS_LEFTスタイル、BS_RIGHTスタイルで設定します。


CreateWindow(
	L"BUTTON", L"Check1",
	WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT,
	10, 10, 120, 25,
	hWnd, (HMENU)IDC_CHECK1, hInst, NULL);

//テキストの右揃え
CreateWindow(
	L"BUTTON", L"Check2",
	WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT,
	10, 40, 120, 25,
	hWnd, (HMENU)IDC_CHECK2, hInst, NULL);

テキストの右揃え