マウスイベント

マウスイベントの処理

キーボードの処理に続いて、マウスのイベント処理について学習します。マウスのイベントは多岐にわたるため、様々なイベントがあります。

サンプルプログラム


では実際にマウスのイベント処理を行うプログラムを見てみましょう。まずは以下のプロジェクトを実行してみてください。

win32proj5-1:WinMain.cpp
ダウンロード
// ************************************
// Ex マウスのイベント処理を行う①
// ************************************
//必要なヘッダーファイルのインクルード
#define STRICT

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

// シンボル定義及びマクロ
#define WINDOW_WIDTH    800
#define WINDOW_HEIGHT   600

//文字列描画用配列
TCHAR   szstr[256] = _T("ボタンを押していません");

//ポイント構造体
POINT  pt = { 5, 5 };

//	インスタンス(グローバル変数)
HINSTANCE hInst;

//	ウィンドウプロシージャのコールバック関数
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	static TCHAR szWindowClass[] = _T("Sample05");
	static TCHAR szTitle[] = _T("マウスイベントを処理するプログラム①");

	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

	if (!RegisterClassEx(&wcex))
	{
		MessageBox(NULL,
			_T("RegisterClassExの処理に失敗しました"),
			_T("Sample05"),
			NULL);

		return 1;
	}

	hInst = hInstance; // グローバル変数に値を入れる

	// The parameters to CreateWindow explained:
	// szWindowClass				: アプリケーションの名前
	// szTitle						: タイトルバーに現れる文字列
	// WS_OVERLAPPEDWINDOW			: 生成するウィンドウのタイプ
	// CW_USEDEFAULT, CW_USEDEFAULT	: 最初に置くポジション (x, y)
	// WINDOW_WIDTH, WINDOW_HEIGHT	: 最初のサイズ (幅, 高さ)
	// NULL							: このウィンドウの親ウィンドウのハンドル
	// NULL							: メニューバー(このサンプルでは使用せず)
	// hInstance					: WinMain関数の最初のパラメータ
	// NULL							: WM_CREATE情報(このアプリケーションでは使用せず)
	HWND hWnd = CreateWindow(
		szWindowClass,
		szTitle,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		WINDOW_WIDTH, WINDOW_HEIGHT,
		NULL,
		NULL,
		hInstance,
		NULL
		);
	//	ウィンドウが生成できなかった場合
	if (!hWnd)
	{
		MessageBox(NULL,
			_T("ウィンドウ生成に失敗しました!"),
			_T("Sample05"),
			NULL);
		return 1;
	}

	// ウィンドウの表示に必要なパラメータ:
	// hWnd		: CreateWindowの戻り値
	// nCmdShow	: WinMainの引数の4番目
	ShowWindow(hWnd,
		nCmdShow);
	UpdateWindow(hWnd);

	// メインのメッセージループ:
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int)msg.wParam;
}

//	ウィンドウプロシージャ(メッセージに対するコールバック関数)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	switch (message)
	{
	case WM_PAINT:
		//	描画処理の開始
		hdc = BeginPaint(hWnd, &ps);
		// 文字列の出力。
		TextOut(hdc,
			pt.x, pt.y,
			szstr, _tcslen(szstr));
		//	ペイント処理の終了
		EndPaint(hWnd, &ps);
		break;
		//キーを押した
		return 0;
	//左クリック
	case WM_LBUTTONDOWN:
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		InvalidateRect(hWnd, NULL, TRUE); //更新
		break;
	case WM_LBUTTONUP:
		break;
	case WM_LBUTTONDBLCLK:
		break;
	case WM_RBUTTONDOWN:
		break;
	case WM_RBUTTONUP:
		break;
	case WM_RBUTTONDBLCLK:
		break;
	case WM_MBUTTONDOWN:
		break;
	case WM_MBUTTONUP:
		break;
	case WM_MBUTTONDBLCLK:
		break;
	case WM_MOUSEMOVE:
		_stprintf_s(szstr,_T("現在の座標(%d,%d)"),LOWORD( lParam ), HIWORD( lParam ) );
		//再描画メッセージを発生させる
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
		break;
	//キーを押した
	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_ESCAPE:
			//終了メッセージを発生させる
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
		break;
	}
	return 0;
}

プログラムを実行すると、ウィンドウが出現し、以下のような文字列が出現します。()内の数値は、ウィンドウ上でのマウスの位置を表します。(図4-1.)

図5-1.プログラムを起動時

プログラムを起動時

したがって、マウスを動かすと、()内の数値は変化します。(図5-2.)

図5-2.マウスを動かしたとき

マウスを動かしたとき

さらに、ウィンドウ内でマウスの左ボタンをクリックすると、その場所に文字列が移動します。

図5-3.クリックをしたとき

クリックをしたとき

キーボードのイベントのプログラムの場合と同様、エスケープキーを押すとウィンドウが閉じてプログラムが終了します。

プログラムの仕組み

マウス関連のイベント

プログラム全体の流れについて説明する前に、マウスのイベントにはどのようなものがあるかを説明しておきます。マウスのイベントには、以下のようなものがありまず。(表7-1.)。

表7-1.マウスのイベントの種類
イベント名内容
WM_LBUTTONDOWNマウスの左ボタンが押された
WM_LBUTTONUPマウスの左ボタンが離された
WM_LBUTTONDBLCLKマウスの左ボタンがダブルクリックされた
WM_RBUTTONDOWNマウスの右ボタンが押された
WM_RBUTTONUPマウスの右ボタンが離された
WM_RBUTTONDBLCLKマウスの右ボタンがダブルクリックされた
WM_MBUTTONDOWNマウスの中央ボタンが押された
WM_MBUTTONUPマウスの中央ボタンが離された
WM_MBUTTONDBLCLKマウスの中央ボタンがダブルクリックされた
WM_MOUSEMOVEマウスの移動

キーボードのイベントの処理の場合同様、switch文でそれぞれのイベントに対する処理を記述していきます。

ダブルクリックのイベントの許可

ただ、今までのキーボードイベントの時とは違い、マウスの処理でダブルクリックのイベントを取得するには、ウィンドウ生成時の設定に若干変更が必要です。39行目のwcex.styleの設定を見てください。

wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

最後に出てくるCS_DBLCLKSは、ダブルクリックを許可することを意味します。これにより、このプログラムはイベントとしてダブルクリックを感知することができるようになります。

マウスの座標の取得

すでに説明したとおり、マウスのイベントのうち、WM_MOUSEMOVEによって、マウスの移動が取得されます。しかし、これで検知されるのは、あくまでも「マウスが移動した」という事実であって、マウスのカーソルがどこにあるかまでは分かりません。

この情報を取得するために利用するのが、lParamです。しかしマウス座標はX座標とY座標と数値が2つ存在するのに対して変数は1つしかりません。なぜでしょう?実は4バイトの型のlParam変数内の上位ビットと下位ビットに分けて、値が格納してあるのです。

そこで登場するのが、HIWORDマクロおよび、LOWORDマクロです。132行目から133行目でこのマクロを使用することで、上位ビットと下位ビットを、分けて取り出してくれるのです。

HIWORD,LOWORDマクロによる画像の取り出し
pt.x = LOWORD( lParam );
pt.y = HIWORD( lParam );

これにより、クライアント領域上でのマウスの座標を取得することができるのです。

図5-4.lParamの値と、HIWORD,LOWORDマクロ

Paramの値と、HIWORD,LOWORDマクロ