핵심 API로 배우는 윈도우 프로그래밍 3장 중 마우스 메시지를 공부하고 정리한 내용입니다.
3-3은 마우스 클릭과 드래그의 마우스 이벤트를 정리한 챕터이다.
예제가 인상깊어 글로 정리한다.
5번예제와 6번예제를 통합한 코드이다.
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <TCHAR.H>
#include <math.h>
#define BSIZE 40
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_QUESTION); //윈도우 아이콘
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //커서 모양
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //배경 색
WndClass.lpszMenuName = NULL; //메뉴 이름
WndClass.lpszClassName = _T("Window Class Name"); //윈도우 클래스 이름
RegisterClass(&WndClass);
hwnd = CreateWindow(_T("Window Class Name"),
_T("Cobaltbru's First Window"), //윈도우 타이틀 이름
WS_OVERLAPPEDWINDOW, //윈도우 스타일
200, //윈도우 위치 X
300, //윈도우 위치 Y
600, //윈도우 가로
400, //윈도우 세로
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, nCmdShow); //윈도우 기본 출력 함수
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
double LengthPts(int x1, int y1, int x2, int y2)
{
return(sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
BOOL InCircle(int x, int y, int mx, int my)
{
if (LengthPts(x, y, mx, my) < BSIZE) return TRUE;
else return FALSE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int x, y;
static BOOL Selection;
int mx, my;
switch (iMsg)
{
case WM_CREATE:
x = 50; y = 50;
Selection = FALSE;
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (Selection)
Rectangle(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
Ellipse(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN:
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (InCircle(x, y, mx, my)) Selection = TRUE;
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_LBUTTONUP:
Selection = FALSE;
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_MOUSEMOVE:
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (Selection)
{
x = mx;
y = my;
InvalidateRgn(hwnd, NULL, TRUE);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, iMsg, wParam, lParam));
}
위 코드는
1. 화면상에 원을 하나 출력하고
2.원 내부를 클릭하면 원에 외접하는 사각형을 출력하고
3.원을 클릭해 드래그 하면 마우스를 따라 움직이게 한다.
코드를 자세히 살펴보자
#define BSIZE 40
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (Selection)
Rectangle(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
Ellipse(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
EndPaint(hwnd, &ps);
break;
기본적으로 원을 출력하는 부분에서 굳이 x와 y 좌표에 일정한 값을 더하고 빼주는 형식을 취해주었다.
처음에는 이해가 가지 않았지만 이것은 Ellipse가 원을 그릴때 먼저 사각형의 좌측상단과 우측하단의 좌표를 받아
내접하는 원을 그린다는 점을 이용하여
x와 y는 원의 중심의 좌표, BSIZE의 정수는 원의 반지름을 표현했다는 것을 깨달았다.
case WM_LBUTTONDOWN:
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (InCircle(x, y, mx, my)) Selection = TRUE;
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_LBUTTONUP:
Selection = FALSE;
InvalidateRgn(hwnd, NULL, TRUE);
break;
WM_LBUTTONDOWN은 마우스를 클릭하고 있을때이다.
mx와 my에 현재 마우스로 클릭하고 있는 좌표를 받는다.
double LengthPts(int x1, int y1, int x2, int y2)
{
return(sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
BOOL InCircle(int x, int y, int mx, int my)
{
if (LengthPts(x, y, mx, my) < BSIZE) return TRUE;
else return FALSE;
}
원의 좌표와 마우스가 클릭한 좌표를 위 함수로 보내는데
위에서 설명한대로 x와 y는 원의 중심이므로 피타고라스의 정리를 이용해 현재 마우스가 클릭한 위치의 좌표와의 거리를 구할 수 있다.
그 거리를 BESIZE 반지름 값과 비교하면 현재 마우스를 클릭한 위치가 원 내부에 있는지 알 수 있는 것이다.
이렇게 함으로써 원 안을 정확히 인식 할 수 있는것이다.
case WM_MOUSEMOVE:
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (Selection)
{
x = mx;
y = my;
InvalidateRgn(hwnd, NULL, TRUE);
}
break;
드래그 입력이 감지되면 마우스의 좌표를 계속 받아온다.
Selection이 TRUE라는 뜻은 마우스가 원 안에 클릭되어있다는 뜻이므로
마우스의 좌표를 계속해서 원의 좌표로 넣어주면 원이 마우스를 따라서 움직일 것이다.
단 x와 y좌표는 원의 중심이므로 마우스로 클릭한 위치를 잡고 드래그하는것이 아니라
마우스가 클릭한 위치에 원의 중심이 붙게 된다.
꽤나 부드럽고 정확하게 따라오는 것을 보고 살짝 감동받았다 (...)
이 공부의 목적인 간단한 미니게임만들기에 한발짝 다가간 느낌
'핵심 API로 배우는 윈도우 프로그래밍' 카테고리의 다른 글
핵심 API로 배우는 윈도우 프로그래밍 연습문제 3장 1~4 (0) | 2022.09.26 |
---|---|
[windowAPI] 마우스 클릭&드래그로 고무줄 직선 그리기 (2) | 2022.09.24 |
핵심 API로 배우는 윈도우 프로그래밍 연습문제 2장 9번 (0) | 2022.09.22 |
핵심 API로 배우는 윈도우 프로그래밍 연습문제 2장 7, 8 (2) | 2022.09.22 |
핵심 API로 배우는 윈도우 프로그래밍 연습문제 2장 4~6 (0) | 2022.09.19 |