色の選択


コモンダイアログ

Windows は、ユーザーに一貫性のある、直感的な操作をサポートしています
例えば、熟練ユーザーは「ファイル」メニューの「保存」アイテムをクリックすれば
ファイルの保存ダイアログが表示されることを知っています

この、ファイルの保存ダイアログは、多くのアプリケーションが表示します
メーカーが異なっていても、素人が作ったプログラムでも、保存の時は同じダイアログです
(稀に、独自のウィンドウを表示させるマニアックなソフトウェアもあるが…)

実は、これはコモンダイアログと呼ばれる
Windows が提供している、標準的なダイアログコントロールなのです

全てのアプリケーションが共通した処理に、共通した UI を提供することで
使用するユーザーは、直感的に、わかりやすくアプリケーションを使えるのです
もちろん開発者も、その分、作業量が減り、より生産性を高めることができます
これは、多くの利用者が Windows を標準の OS に選択した理由のひとつでもあるでしょう

もし、あなたのアプリケーションが、ファイルを保存する時、印刷するとき、フォントを選択する時
他のアプリケーションとは違う、独自のダイアログを表示させれば
ユーザーは操作方法がなかなか理解できず、単純な作業に時間を奪われるかもしれません
高度なソフトウェアを開発するには、標準コントロールの存在が不可欠なのです


色の設定ダイアログ

今回は、色をユーザーに選択してもらう「色の設定」ダイアログを表示させてみましょう
画像関連のソフトウェアで、多く用いられるダイアログです

色の設定ダイアログを表示するには ChooseColor() 関数を使います
この関数は、指定したスタイルで、モーダルダイアログボックスを表示させます

BOOL ChooseColor(LPCHOOSECOLOR lpcc);

lpcc には、設定情報を格納した CHOOSECOLOR 構造体へのポインタを指定します
戻り値は、ユーザーが色を選択したら TRUE、そうでなければ FALSE を返します
キャンセルボタンを選択されり、エラーが発生した場合は FALSE が返ります

CHOOSECOLOR 構造体は、次のように定義されています
typedef struct {   // cc 
    DWORD        lStructSize; 
    HWND         hwndOwner; 
    HWND         hInstance; 
    COLORREF     rgbResult; 
    COLORREF*    lpCustColors; 
    DWORD        Flags; 
    LPARAM       lCustData; 
    LPCCHOOKPROC lpfnHook; 
    LPCTSTR      lpTemplateName; 
} CHOOSECOLOR;
lStructSize には、この構造体のサイズを指定します
hwndOwner は、ダイアログのオーナーウィンドウを指定します
オーナーウィンドウが存在しない場合は NULL を指定することができます

hInstance は、ダイアログテンプレートを用いる場合に
使用するダイアログテンプレートを含む、モジュールのインスタンスを指定します
ダイアログテンプレートについては、後で説明します

rgbResult は、ダイアログが最初に選択している初期カラーを指定します
ユーザーが色を選択してダイアログを閉じた後は、選択した色が格納されています
このメンバの色を使えない場合は、それに一番近い色をシステムが設定します

lpCistColors には、ダイアログが持っている基本色を格納する
16個の COLORREF 配列へのポインタを指定します
ユーザーは、作成した色をダイアログのパレット領域に一時保存することができ
この変数の配列には、そのダイアログの基本色が格納されます

Flags は、ダイアログボックスの初期化フラグを指定します
このメンバには、以下の定数を組み合わせて指定することができます

定数解説
CC_ENABLEHOOK lpfnHook メンバで指定されたフック関数を有効にする
CC_ENABLETEMPLATE nInstance メンバと lpTemplateName メンバで指定された
ダイアログボックステンプレートを使ってダイアログを作成します
CC_ENABLETEMPLATEHANDLE hInstance メンバがロード済みのダイアログボックステンプレートを含む
メモリブロックを指していることを表す
このフラグが指定されている場合、lpTemplateName は無視される
CC_FULLOPEN カスタムカラー作成部を含む
色の設定ダイアログボックス全体を表示する
CC_PREVENTFULLOPEN 「色の作成」ボタンを無効にする
CC_RGBINIT rgbResult メンバで指定した値を
初期設定カラーとしてダイアログに使用します
CC_SHOWHELP ダイアログボックスに「ヘルプ」ボタンを追加する
このフラグを指定した場合、hwndOwner を指定しなければなりません

lCustData メンバは、lpfnHook で指定されたフック関数に渡す追加情報を指定します
データは、WM_INITDIALOG めっせーじの LPARAM 型引数に渡されます
lpfnHook は、フック関数へのポインタを指定します
フック関数については、次の章で詳しく解説しますが、簡単に説明するならサブクラス化です
コモンダイアログは、独自のメッセージ処理関数を使ってカスタマイズすることができるのです

lpTemplateName には、使用するダイアログテンプレートの名前を指定します
hInstance メンバで指定したモジュールの指定したテンプレートを使用するようになります

ダイアログテンプレートとは、外観を変更するときに用います
コモンダイアログに、独自のコントロールを貼りつけたい場合や
丸々、独自のダイアログをつけたい場合などに、フック関数と合わせて拡張したりできます
ダイアログテンプレートについても、後ほど詳しく解説いたします

さて、これだけで、複雑な色の設定ウィンドウをアプリケーションで使うことができます
自分で同じようなものを作成することを考えれば、かなり便利だと思うでしょう
他のコモンダイアログも、同じように1つの専用関数と1つの専用構造体を使用します
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static CHOOSECOLOR cc = {0};
	static COLORREF color = 0 , CustColors[16];

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		cc.lStructSize	= sizeof (CHOOSECOLOR);
		cc.hwndOwner	= hWnd;
		cc.rgbResult	= color;
		cc.lpCustColors	= CustColors;
		cc.Flags	= CC_FULLOPEN | CC_RGBINIT;
		return 0;
	case WM_LBUTTONUP:
		if (!ChooseColor(&cc)) return 0;
		SetClassLong(hWnd , GCL_HBRBACKGROUND ,
			(LONG)CreateSolidBrush(cc.rgbResult));
		InvalidateRect(hWnd , NULL , TRUE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


このプログラムは、ウィンドウのクライアント領域を左クリックすると
今回の主役である、色の選択ダイアログボックスが表示されます
色を選択すると、プログラムはクライアント領域の背景色としてその色を選択します


ChooseColor()

BOOL ChooseColor(LPCHOOSECOLOR lpcc);

色の選択ダイアログボックスを表示します

lpcc - 設定情報を格納した CHOOSECOLOR 構造体へのポインタを指定します

戻り値 - ユーザーが色を選択したら TRUE、そうでなければ FALSE



戻る次のページへ