반응형

저번에는 MFC의 구조 및 간단한 입출력에 대해서 알아보았습니다.

이번에는 MFC 프로그래밍의 제어 메시지를 처리하는 방법에 대해서 알아보도록 하겠습니다.

.

.

.

키보드 입력

.

.

.

MFC 프로그래밍에서 키보드로 입력을 받기 위해서는 우선 WM_KEYDOWN 을 이용하여 메시지로 방향키를 받을 수 있습니다. 여기서 입력하게 되는 값들은 wParam에 가상 키의 값으로 저장이 되어있으며, 

방향키의 가상키로는 아래와 같이 있습니다.

.

.

.

위에서 말하는 wParam 은 윈도가 어떻게 변했는지 알려주는 상수로

SIZE_MAXIMIZED : 윈도우 최대화

SIZE_MINIMIZED : 윈도우 최소화

SIZE_RESTORED : 윈도우 크기가 변경됨

등이 있습니다.

.

.

.

IParam은 변경된 윈도우 클라이언트의 크기를 나타내며

HIWORD : 변경된 윈도우 높이

LOWORD : 변경된 윈도우 너비

등이 있습니다.

.

.

.

타이머 메시지

.

.

.

타이머 메시지는 말그대로 컴퓨터에 시간 간격을 설정하여 WM_TIMER 메시지를 프로그램에 보내도록 하는 기능을 합니다.

.

.

타이머 메시지의 설정함수로는 SetTimer() 함수 가 있으며 그 구조는 아래와 같습니다.

UINT_PTR SetTimer(
	HWND hwnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC IpTimerFunc
);

 매개변수

.

hwnd : 윈도우 핸들

nIDEvent : 타이머 ID, 여러 개의 타이머를 구분하기 위한 정수

uElapse : 시간 간격 milisec(1000/1초)

IpTimerFunc : 시간 간격마다 수행할 함수(NULL이라고 쓰면 WndProc()가 타이머 메시지(WM_TIMER)를 처리합니다.)

.

.

처리방법

.

case WM_CREATE:
	SetTimer(hwnd,1,80,NULL);
    SetTimer(hwnd,2,100,NULL);
    break;
case WM_TIMER:
	switch (wParam) {
    case 1 : // 0.08 초 간격으로 실행
    case 2 : // 0.1 초 간격으로 실행
    .
    .
    .
}

.

.

.

마우스 이벤트 

.

.

.

키보드 이벤트와 비슷한 형식이며,

마우스 이벤트를 처리하기 위해서는 

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_MOUSEMOVE

가 있습니다.

.

.

마우스를 이용하여 이벤트를 처리하게 되면 윈도우 클라이언트 창에서 좌표를 이용하여 처리하게 될 경우가 많이 있습니다. 그럴 때 마우스의 좌표를 구하기 위해서는 

int x = LOWORD(IParam)

int y = HIWORD(IParam)

등이 있습니다.

.

.

.

래스터 연산

.

.

.

래스터 연산은 윈도우의 배경색과 그리는 색을 연산한 결과 색상으로 그림을 그려주는 연산을 수행합니다.

.

.

래스터 연산의 종류

.

.

R2_COPYPEN

R2_XORPEN

R2_NOT

R2_NOTCOPYPEN

R2_NOTXORPEN

등이 있습니다.

.

.

.

위에서 배운 개녕을 더 잘 이해하기 위해서 간단한 예제를 수행해보도록 하겠습니다.

.

.

.

간단하게 방향키를 활용하여 사각형 안에서만 원이 이동되도록 해보겠습니다.

#include <windows.h>
#include <TCHAR.H>
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpszCmdLine, int nCmdShow)
	// UNICODE 사용시 wWinMain() 형태 	
	// hPrevInstance 이전 인스턴스 항상 0값
	// lpszCmdLine > 외부에서 (내부로) 입력받는 변수
	// nCmdShow 윈도우 출력 형태에 관련한 값
{
	HWND     hwnd;
	MSG		 msg;
	WNDCLASS WndClass;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;	//height, vertical redraw
	WndClass.lpfnWndProc = WndProc;		// Proc 설정
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = hInstance;
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	// 형변환
	WndClass.lpszMenuName = NULL;
	WndClass.lpszClassName = _T("Window Class Name");
	RegisterClass(&WndClass);		// WndClass 등록
	hwnd = CreateWindow(_T("Window Class Name"),
		_T("Jung-story"),		
		WS_OVERLAPPEDWINDOW,		// 윈도우 스타일
		600, 400,					// 창출력좌표 x, y 
		600, 400,					// 창크기 x, y축
		NULL,						// 부모 윈도우
		NULL,						// 메뉴바 핸들
		hInstance,					// 인스턴스
		NULL						// 여분, NULL
		);
	ShowWindow(hwnd, nCmdShow);		// 윈도우 출력, WM_PAINT 출력내용 가져옴
	UpdateWindow(hwnd);				// WM_PAINT 출력내용 발생해서 출력하도록
									// hwnd 핸들을 통해 보여주고 갱신

	//ShowWindow(hwnd, SW_SHOW);	// 위와 같음
	//UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))	// 메시지 큐의 메시지를 가져옴
	{
		TranslateMessage(&msg);		// 키입력에 반응하는 메시지 변환, WM_KEYDOWN (키가 눌릴때) WM_CHAR 메시지 발생
		DispatchMessage(&msg);		// WndProc() 함수 호출과 WndProc()으로 메세지 전달
	}								// 종료는 WM_QUIT 발생할때 FALSE 리턴하면서 종료
	return (int)msg.wParam;			// wParam, lParam 윈도우 크기가 어떻게 변했는지, 변경된 클라이언트, 키보드, 마우스 값

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam)
	//	WinDef.h 에서 정의
	//	wPram > unsigned ptr, lParam > long ptr 
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x, y;
	static RECT rectView;
	HPEN hPen, oldPen;

	switch (iMsg)
	{
	case WM_CREATE:
		x = 20; y = 20;
		return 0;

	case WM_KEYDOWN:
		if (wParam == VK_RIGHT) {	// 오른쪽 직접입력
			x += 40;
			if (x + 20 > rectView.right) {
				x -= 40;
			}
		}
		else if (wParam == VK_LEFT) {
			x -= 40;
			if (x - 20 < rectView.left) {
				x += 40;
			}
		}
		else if (wParam == VK_UP) {
			y -= 40;
			if (y - 20 < rectView.top) {
				y += 40;
			}
		}
		else if (wParam == VK_DOWN) {
			y += 40;
			if (y + 20 > rectView.bottom) {
				y -= 40;
			}
		}
		else if (wParam == VK_HOME) {	// 홈키를 입력하면 원위치로 이동
			x = 20;
			y = 20;
		}

		InvalidateRgn(hwnd, NULL, TRUE);
		break;

	case WM_PAINT:
		GetClientRect(hwnd, &rectView);	// 위에서 설정한 윈도우크기만큼 만들어짐
		hdc = BeginPaint(hwnd, &ps);
		hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
		oldPen = (HPEN)SelectObject(hdc, hPen);	// 새로운 펜 사용 선언
		Rectangle(hdc, 0, 0, 40 * (int)(rectView.right / 40), 40 * (int)(rectView.bottom / 40));
		SelectObject(hdc, oldPen);	// 이전의 펜으로 돌아감
		DeleteObject(hPen);
		Ellipse(hdc, x - 20, y - 20, x + 20, y + 20);
		EndPaint(hwnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

.

.

이 코드에서 포인트라면 rectView를 이용하여 원이 사각형밖으로 이동하지 못하도록 값을 계산해 주었습니다.

.

.

.

.

.

.

간단한 방향키를 이용하여 에벌레를 움직이기

#include <windows.h>
#include <TCHAR.H>
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpszCmdLine, int nCmdShow)
	// UNICODE 사용시 wWinMain() 형태 	
	// hPrevInstance 이전 인스턴스 항상 0값
	// lpszCmdLine > 외부에서 (내부로) 입력받는 변수
	// nCmdShow 윈도우 출력 형태에 관련한 값
{
	HWND     hwnd;
	MSG		 msg;
	WNDCLASS WndClass;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;	//height, vertical redraw
	WndClass.lpfnWndProc = WndProc;		// Proc 설정
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = hInstance;
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	// 형변환
	WndClass.lpszMenuName = NULL;
	WndClass.lpszClassName = _T("Window Class Name");
	RegisterClass(&WndClass);		// WndClass 등록
	hwnd = CreateWindow(_T("Window Class Name"),
		_T("Jung-story"),		// 타이틀바, 
		WS_OVERLAPPEDWINDOW,		// 윈도우 스타일
		600, 400,					// 창출력좌표 x, y 
		600, 400,					// 창크기 x, y축
		NULL,						// 부모 윈도우
		NULL,						// 메뉴바 핸들
		hInstance,					// 인스턴스
		NULL						// 여분, NULL
		);
	ShowWindow(hwnd, nCmdShow);		// 윈도우 출력, WM_PAINT 출력내용 가져옴
	UpdateWindow(hwnd);				// WM_PAINT 출력내용 발생해서 출력하도록
									// hwnd 핸들을 통해 보여주고 갱신

	//ShowWindow(hwnd, SW_SHOW);	// 위와 같음
	//UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))	// 메시지 큐의 메시지를 가져옴
	{
		TranslateMessage(&msg);		// 키입력에 반응하는 메시지 변환, WM_KEYDOWN (키가 눌릴때) WM_CHAR 메시지 발생
		DispatchMessage(&msg);		// WndProc() 함수 호출과 WndProc()으로 메세지 전달
	}								// 종료는 WM_QUIT 발생할때 FALSE 리턴하면서 종료
	return (int)msg.wParam;			// wParam, lParam 윈도우 크기가 어떻게 변했는지, 변경된 클라이언트, 키보드, 마우스 값

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam)
	//	WinDef.h 에서 정의
	//	wPram > unsigned ptr, lParam > long ptr 
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x[2], y[2],xStep,yStep,flag;
	static RECT rectView;
	HPEN hPen, oldPen;
	int tmpx, tmpy;

	switch (iMsg)
	{
	case WM_CREATE:
		x[0] = 20; y[0] = 20;
		x[1] = 60; y[1] = 20;
		xStep = 40; yStep = 0;
		return 0;

	case WM_KEYDOWN:
		switch (wParam) {

		case VK_RETURN:
			flag = 1-flag;
			if (flag) SetTimer(hwnd, 1, 100, NULL);	// 움직임 시작
			else KillTimer(hwnd, 1);	// 움직임 중지
			break;
		case VK_RIGHT:	//오른쪽 이동
			xStep = 40;
			yStep = 0;
			break;
		case VK_LEFT:	// 왼쪽 이동
			xStep = -40;
			yStep = 0;
			break;
		case VK_UP:	// 위쪽 이동
			xStep = 0;
			yStep = -40;
			break;
		case VK_DOWN:	// 아래쪽 이동
			xStep = 0;
			yStep = 40;
			break;
		InvalidateRgn(hwnd, NULL, TRUE);
		break;
		}
	case WM_PAINT:
		GetClientRect(hwnd, &rectView);	// 위에서 설정한 윈도우크기만큼 만들어짐
		hdc = BeginPaint(hwnd, &ps);
		SelectObject(hdc, CreatePen(PS_SOLID, 1, RGB(255, 255, 255)));
		Rectangle(hdc, 0, 0, 40 * (int)(rectView.right / 40), 40 * (int)(rectView.bottom / 40));
		SelectObject(hdc, CreatePen(PS_SOLID,2,RGB(255,0,0)));	// 빨간색 원 그리기 0,0에
		Ellipse(hdc, x[0] - 20, y[0] - 20, x[0] + 20, y[0] + 20);
		SelectObject(hdc, CreatePen(PS_SOLID, 2, RGB(0, 0, 255)));	// 파란색 원 그리기 0,0에
		Ellipse(hdc, x[1] - 20, y[1] - 20, x[1] + 20, y[1] + 20);
		EndPaint(hwnd, &ps);
		break;
	
	case WM_TIMER:
		GetClientRect(hwnd, &rectView);
		tmpx = x[0];
		tmpy = y[0];
		x[0] += xStep; y[0] += yStep;
		if (x[0] - 20 < rectView.left || x[0] + 20 > rectView.right) {
			x[0] = tmpx;
			y[0] = tmpy;
		}
		else x[1] = tmpx; 
		
		if (y[0] - 20 < rectView.top || y[0] + 20 > rectView.bottom) {
			x[0] = tmpx;
			y[0] = tmpy;
		}
		else y[1] = tmpy;
		InvalidateRgn(hwnd, NULL, true);
		break;

	case WM_DESTROY:
		KillTimer(hwnd, 1);
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

.

.

.

실행 영상

.

.

.

이 코드에서 포인트는 flag를 설정하여 Enter키를 입력하였을 때 값이 스위칭돼서 움직임과 정지를 계산해 주었으며,

WM_TIMER 부분에서 각원의 지름을 이용하여 계산해주었습니다.

.

.

.

마우스 클릭 시 이미지 변화

#include <windows.h>
#include <TCHAR.H>
#include <math.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpszCmdLine, int nCmdShow)
	// UNICODE 사용시 wWinMain() 형태 	
	// hPrevInstance 이전 인스턴스 항상 0값
	// lpszCmdLine > 외부에서 (내부로) 입력받는 변수
	// nCmdShow 윈도우 출력 형태에 관련한 값
{
	HWND     hwnd;
	MSG		 msg;
	WNDCLASS WndClass;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;	//height, vertical redraw
	WndClass.lpfnWndProc = WndProc;		// Proc 설정
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = hInstance;
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	// 형변환
	WndClass.lpszMenuName = NULL;
	WndClass.lpszClassName = _T("Window Class Name");
	RegisterClass(&WndClass);		// WndClass 등록
	hwnd = CreateWindow(_T("Window Class Name"),
		_T("Jung-story"),		// 
		WS_OVERLAPPEDWINDOW,		// 윈도우 스타일
		600, 400,					// 창출력좌표 x, y 
		600, 400,					// 창크기 x, y축
		NULL,						// 부모 윈도우
		NULL,						// 메뉴바 핸들
		hInstance,					// 인스턴스
		NULL						// 여분, NULL
		);
	ShowWindow(hwnd, nCmdShow);		// 윈도우 출력, WM_PAINT 출력내용 가져옴
	UpdateWindow(hwnd);				// WM_PAINT 출력내용 발생해서 출력하도록
									// hwnd 핸들을 통해 보여주고 갱신

	//ShowWindow(hwnd, SW_SHOW);	// 위와 같음
	//UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))	// 메시지 큐의 메시지를 가져옴
	{
		TranslateMessage(&msg);		// 키입력에 반응하는 메시지 변환, WM_KEYDOWN (키가 눌릴때) WM_CHAR 메시지 발생
		DispatchMessage(&msg);		// WndProc() 함수 호출과 WndProc()으로 메세지 전달
	}								// 종료는 WM_QUIT 발생할때 FALSE 리턴하면서 종료
	return (int)msg.wParam;			// wParam, lParam 윈도우 크기가 어떻게 변했는지, 변경된 클라이언트, 키보드, 마우스 값

}

float LengthPts(int x1, int y1, int x2, int y2) {
	return (sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
int BSIZE = 20;
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)
	//	WinDef.h 에서 정의
	//	wPram > unsigned ptr, lParam > long ptr 
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x, y;
	static BOOL Selection;
	HBRUSH hBrush, oldBrush;
	HPEN hPen, oldPen;
	int mx, my;

	switch (iMsg)
	{
	case WM_CREATE:
		x = 20; y = 20;
		Selection = FALSE;
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		if(Selection) {	// 원이 선택 되었을시
			hBrush = CreateSolidBrush(RGB(0,255, 0));	// 면색
			oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
			hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));	// 선색
			oldPen = (HPEN)SelectObject(hdc, hPen);
		}
		Ellipse(hdc, x - 20, y - 20, x + 20, y + 20);
		EndPaint(hwnd, &ps);
		break;
	case WM_LBUTTONDOWN:	// 왼쪽 마우스 버튼 클릭시
		mx = LOWORD(lParam);	// 마우스 x좌표 
		my = HIWORD(lParam);	// 마우스 y좌표

		if (InCircle(x, y, mx, my)) {
			Selection = TRUE;	// 마우스 클릭시 TRUE로 토글
		}
		InvalidateRgn(hwnd, NULL, TRUE);
		break;

	case WM_LBUTTONUP:	// 왼쪽 마우스 버튼은 떼면
		Selection = FALSE;	
		InvalidateRgn(hwnd, NULL, TRUE);
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

.

.

.

 

실행 영상

.

.

.

이 코드에서 포인트는 math.h를 이용하여 InCircle함수에서 원의 내부의 크기를 계산해주는 것과

Selection을 두어 마우스의 클릭을 조절하는 것입니다.

.

.

.

위의 예제에 이어서 래스터 연산 및 Drag 예제

#include <windows.h>
#include <TCHAR.H>
#include <math.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
	WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpszCmdLine, int nCmdShow)
	// UNICODE 사용시 wWinMain() 형태 	
	// hPrevInstance 이전 인스턴스 항상 0값
	// lpszCmdLine > 외부에서 (내부로) 입력받는 변수
	// nCmdShow 윈도우 출력 형태에 관련한 값
{
	HWND     hwnd;
	MSG		 msg;
	WNDCLASS WndClass;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;	//height, vertical redraw
	WndClass.lpfnWndProc = WndProc;		// Proc 설정
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = hInstance;
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	// 형변환
	WndClass.lpszMenuName = NULL;
	WndClass.lpszClassName = _T("Window Class Name");
	RegisterClass(&WndClass);		// WndClass 등록
	hwnd = CreateWindow(_T("Window Class Name"),
		_T("Jung-story"),		// 
		WS_OVERLAPPEDWINDOW,		// 윈도우 스타일
		600, 400,					// 창출력좌표 x, y 
		600, 400,					// 창크기 x, y축
		NULL,						// 부모 윈도우
		NULL,						// 메뉴바 핸들
		hInstance,					// 인스턴스
		NULL						// 여분, NULL
		);
	ShowWindow(hwnd, nCmdShow);		// 윈도우 출력, WM_PAINT 출력내용 가져옴
	UpdateWindow(hwnd);				// WM_PAINT 출력내용 발생해서 출력하도록
									// hwnd 핸들을 통해 보여주고 갱신

	//ShowWindow(hwnd, SW_SHOW);	// 위와 같음
	//UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))	// 메시지 큐의 메시지를 가져옴
	{
		TranslateMessage(&msg);		// 키입력에 반응하는 메시지 변환, WM_KEYDOWN (키가 눌릴때) WM_CHAR 메시지 발생
		DispatchMessage(&msg);		// WndProc() 함수 호출과 WndProc()으로 메세지 전달
	}								// 종료는 WM_QUIT 발생할때 FALSE 리턴하면서 종료
	return (int)msg.wParam;			// wParam, lParam 윈도우 크기가 어떻게 변했는지, 변경된 클라이언트, 키보드, 마우스 값

}

float LengthPts(int x1, int y1, int x2, int y2) {
	return (sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
int BSIZE = 20;
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)
	//	WinDef.h 에서 정의
	//	wPram > unsigned ptr, lParam > long ptr 
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x, y;
	static BOOL Selection,Drag;
	HBRUSH hBrush, oldBrush;
	HPEN hPen, oldPen;
	int mx, my;
	static int oldX, oldY;
	int endX=0, endY=0;
	switch (iMsg)
	{
	case WM_CREATE:
		x = 20; y = 20; 
		oldX = 20; oldY = 20;
		Selection = FALSE;
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		if (Selection) {	// 원이 선택 되었을시
			hBrush = CreateSolidBrush(RGB(0, 255, 0));	// 면색
			oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
			hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));	// 선색
			oldPen = (HPEN)SelectObject(hdc, hPen);
		}
		Ellipse(hdc, x - 20, y - 20, x + 20, y + 20);
		EndPaint(hwnd, &ps);
		break;
	case WM_LBUTTONDOWN:	// 왼쪽 마우스 버튼 클릭시
		mx = LOWORD(lParam);	// 마우스 x좌표 
		my = HIWORD(lParam);	// 마우스 y좌표

		if (InCircle(x, y, mx, my)) {
			Selection = TRUE;	// 마우스 클릭시 TRUE로 토글
			Drag = TRUE;
		}
		InvalidateRgn(hwnd, NULL, TRUE);
		break;

	case WM_LBUTTONUP:	// 왼쪽 마우스 버튼은 떼면
		Selection = FALSE;
		Drag = FALSE;
		oldX = x; // static 으로 남아있기 때문에 초기화를 해야함
		oldY = y;
		InvalidateRgn(hwnd, NULL, TRUE);
		break;
	
	case WM_MOUSEMOVE:
		hdc = GetDC(hwnd);
		if (Drag && Selection) {
			SetROP2(hdc, R2_XORPEN);	// 펜의 XOR 연산 예) 흰바탕일때 검정색
			SelectObject(hdc, (HPEN)GetStockObject(WHITE_PEN));

			endX = LOWORD(lParam);
			endY = HIWORD(lParam);
			MoveToEx(hdc, x, y, NULL);	// 지우기 : 흰 바탕 XOR 검은 펜 = 흰 선
			LineTo(hdc, oldX, oldY);

			MoveToEx(hdc, x, y, NULL);	// 그리기 : 흰 바탕 XOR 흰 펜 = 검은 선
			LineTo(hdc, endX, endY);

			oldX = endX; oldY = endY;	 // 현 지점을 이전 지점으로 설정

		}
		ReleaseDC(hwnd, hdc);
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

.

.

.

실행 영상

.

.

.

이 코드에서 포인트는 WM_MOUSEMOVE를 이용하여 직선을 그려주고 지워주는 작업을 하는 부분이라고 생각합니다.

.

.

.

이렇게 오늘은 MFC 프로그래밍의 제어 메시지 처리의 개념과 예제에 대해서 알아보았습니다.

반응형

+ Recent posts