左クリックした位置に点を描画する 

Win32 API
スポンサーリンク

この記事では、クライアント領域を左クリックするとその位置に点(正確には小さい円)を描画するWin32 APIアプリケーション(GUI)の作成方法について説明しています。

環境
・Windows8.1
・Visual Studio2019 Community

スポンサーリンク

作成方法

Visual Studio2019 Communityで開発しています。

Win32アプリケーションのプロジェクトの作成方法はこちらの記事の「何もしないウィンドウを作成する手順」と「cppファイルの追加」を参考にしてください。

以下のコードも文字セットはマルチバイト文字セットを使用しています。プロジェクトの文字セットをマルチバイト文字セットに設定してください。設定方法は上の記事で紹介しています。

追加したcppファイルに以下のコードをコピペします。そのあとf5キー押下で実行できます。(下のコードを実際にコピペしてから実行して動作確認しています)

コード

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>

POINT LdownPt;			// 左クリックした位置

int Draw(HWND hWnd, HDC hdc);

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	int id;
	HDC hdc;
	PAINTSTRUCT ps;

	switch (msg) {
	case WM_LBUTTONDOWN:		//マウス左ボタン押下時のメッセージ

		LdownPt.x = GET_X_LPARAM(lp);
		LdownPt.y = GET_Y_LPARAM(lp);

		InvalidateRect(hWnd, NULL, FALSE);
		break;

	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		Draw(hWnd, hdc);
		EndPaint(hWnd, &ps);
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return (DefWindowProc(hWnd, msg, wp, lp));
	}
	return 0L;
}

BOOL InitApp(HINSTANCE hInst, LPCSTR szClassName)
{
	WNDCLASS wc;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInst;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = "GR";
	wc.lpszClassName = (LPCSTR)szClassName;
	return (RegisterClass(&wc));
}

BOOL InitInstance(HINSTANCE hInst, LPCSTR szClassName, int nCmdShow)
{
	HWND hWnd;

	hWnd = CreateWindow(szClassName,
		"点を描画",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		500,
		500,
		NULL,
		NULL,
		hInst,
		NULL);
	if (!hWnd)
		return FALSE;
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	return TRUE;
}



int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
	LPSTR lpsCmdLine, int nCmdShow)
{
	MSG msg;
	char szClassName[] = "drawPt";

	if (!hPrevInst) {
		if (!InitApp(hCurInst, szClassName))
			return FALSE;
	}
	if (!InitInstance(hCurInst, szClassName, nCmdShow)) {
		return FALSE;
	}
	while (GetMessage(&msg, NULL, NULL, NULL)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

// 描画
int Draw(HWND hWnd, HDC hdc)
{
	HPEN hPen, hOldPen;

	hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	hOldPen = (HPEN)SelectObject(hdc, hPen);

	Ellipse(hdc,    
		LdownPt.x - 3,
		LdownPt.y - 3,
		LdownPt.x + 3,
		LdownPt.y + 3
	);

	SelectObject(hdc, hOldPen);
	DeleteObject(hPen);

	return 0;
}

コードの大雑把な説明

WndProc(ウィンドウプロシージャ)に関することだけ簡単に説明します。

クライアント領域上で左クリックするとメッセージWM_LBUTTONDOWNが発生します(16行目)。

このメッセージが発生したときはウィンドウプロシージャの引数LPARAM lpにクリックした位置(座標)が格納されています。GET_X_LPARAM関数を使うとその座標を取得できます。

グローバル変数LdownPt.x,LdownPt.yに左クリックされたx、y座標を格納します(18,19行目)。

無効領域を発生させクライアント領域の再描画を促します(21行目)。

メッセージWM_PAINT(24行目)が発生しそのブロック内で描画関数Draw(102行目。自作関数)を呼び出して描画をします。

点を描画する部分はEllipse関数(109行目)を使用しています。この関数は正確には円(楕円)を描画する関数です。

点を描画する関数としてsetpixelがありますが、本当に点(ピクセル)で見づらいのでEllipseを使って小さな円を点として描画しています。

この記事は以上です。