非クライアントエリアのマウスメッセージ


特殊な位置のクリック

まれに、クライアントエリア以外の位置でクリックされたマウスメッセージを処理したい場合があります
タイトルバーなどに対するマウスメッセージです

これらのメッセージは通常、DefWindowProc() に渡され
ウィンドウの移動やサイズの変更などに利用されていますが
プログラム側でこれを受け取り、独自の処理を行うことも可能です

非クライアントエリアのマウスメッセージは次のようになっています

ボタン押した離したダブルクリックした
WM_NCLBUTTONDOWNWM_NCLBUTTONUPWM_NCLBUTTONDBLCLK
中央WM_NCMBUTTONDOWNWM_NCMBUTTONUPWM_NCMBUTTONDBLCLK
WM_NCRBUTTONDOWNWM_NCRBUTTONUPWM_NCRBUTTONDBLCLK

また、マウスカーソルの非クライアントエリアの移動はWM_NCMOUSEMOVE が発生します
非クライアントエリアのマウスメッセージは、全て通常のマウスメッセージに対応しています
そのため、動作についてはもはや説明不要でしょう

しかし、大きく違うのが受け取るパラメータの内容です
第三引数の WPARAM には非クライアントエリアの場所を表す値で
これを調べることで、非クライアントエリアのどの部分が押されたのかを知ることができます

定数解説
HTBORDER サイズ変更される境界線を持たないウィンドウ境界内にあります
HTBOTTOM ウィンドウ境界の下端の線上にあります
HTBOTTOMLEFT ウィンドウ境界の左下隅にあります
HTBOTTOMRIGHT ウィンドウ境界の右下隅にあります
HTCAPTION タイトル バーの領域内にあります
HTCLIENT クライアント領域内にあります
HTERROR スクリーンの背景上またはウィンドウの区切り線上にあります
これは、DefWindowProc Windows 関数が
エラーを示すシステム ビープ音を発生するということ以外は HTNOWHERE と同じです
HTGROWBOX サイズ ボックス内にあります
HTHSCROLL 水平スクロール バー内にあります
HTLEFT ウィンドウ境界の左端の線上にあります
HTMAXBUTTON 最大表示ボタン内にあります
HTMENU メニュー領域内にあります
HTMINBUTTON アイコン化ボタン内にあります
HTNOWHERE スクリーンの背景かウィンドウの区切り線上にあります
HTREDUCE アイコン化ボタン内にあります
HTRIGHT ウィンドウ境界の右端の線上にあります
HTSIZE サイズ ボックス内にあります (HTGROWBOX と同じです)
HTSYSMENU コントロール メニュー内、または子ウィンドウのクローズ ボタン内にあります
HTTOP ウィンドウ境界の上端の線上にあります
HTTOPLEFT ウィンドウ境界の左上隅にあります
HTTOPRIGHT ウィンドウ境界の右上隅にあります
HTTRANSPARENT 現在ほかのウィンドウに覆い隠されているウィンドウ内にあります
HTVSCROLL 垂直スクロール バー内にあります
HTZOOM 最大表示ボタン内にあります

HT_CLIENT などが非クライアントエリアのメッセージで送られてくることはありません
これは、次の章で説明するヒットテストのためのものです

また、第四引数の LPARAM にはマウスの座標が入っています
ただしこの座標は、スクリーン全体からみた座標です
つまり、通常はディスプレイの左上を 0 , 0 とします
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;
	static TCHAR strLocation[128];
	static unsigned short int x = 0 , y = 0;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_NCLBUTTONDOWN:
		x = LOWORD(lp);
		y = HIWORD(lp);
		wsprintf(strLocation , "x座標 = %d\ny座標 = %d\nHITTEST = %d" , x , y , wp);
		InvalidateRect(hwnd , NULL , TRUE);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd , &ps);

		GetClientRect(hwnd , &rect);
		DrawText(hdc , strLocation , -1 , &rect , DT_LEFT);

		EndPaint(hwnd , &ps);
		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(WHITE_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 ,
			400 , 200 ,
			NULL , NULL , hInstance , NULL
	);

	if (hwnd == NULL) return -1;

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


このプログラムは WM_NCLBUTTONDOWN を DefWindowProc() に渡しません
そのため、タイトルバーや終了ボタンなどを押しても何も処理されません

非クライアント領域をクリックすると、マウスの座標などが描画されます
特に、座標がスクリーン全体からみた座標であることに注目してください



前のページへ戻る次のページへ