학원/경일게임아카데미

21. 열네번째 수업과제 [드래그 앤 드롭]

셩잇님 2022. 12. 22. 21:54
반응형

경일게임아카데미 프로그래밍반 28기 14일차 수업과제 (2021. 04. 27)

 

 

 


 

 

 

오늘은 WIN32 API을 마우스를 활용하여 드래그 앤 드롭 기능을 제작해봅시다!

과제1 - 아이콘 드래그 앤 드롭
과제2 - 탐색기 창 각 끄트머리 잡고 드래그 앤 드롭

이하 과제 1.

#include "stdafx.h"

HINSTANCE _hInstance;
HWND _hWnd;
LPCTSTR _lpszClass = TEXT("경일 28기 이시영 :-) ");

void setWindowsSize(int x, int y, int width, int height);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int cmdShow)
{
	_hInstance = hInstance;

	MSG message;
	WNDCLASS wndClass;

	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hInstance = hInstance;
	wndClass.lpfnWndProc = (WNDPROC)WndProc;
	wndClass.lpszClassName = WINNAME;
	wndClass.lpszMenuName = NULL;
	wndClass.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&wndClass);

	_hWnd = CreateWindow(WINNAME, WINNAME, WS_OVERLAPPEDWINDOW, WINSTARTX, WINSTARTY, WINSIZEX, WINSIZEY, NULL, (HMENU)NULL, hInstance, NULL);

	setWindowsSize(WINSTARTX, WINSTARTY, WINSIZEX, WINSIZEY);
	ShowWindow(_hWnd, cmdShow);

	while (GetMessage(&message, 0, 0, 0))
	{
		TranslateMessage(&message);
		DispatchMessage(&message);
	}
	return message.wParam;
}

POINT _ptMouse;
RECT _rc;
bool _flag = false;
int _disX = 0;
int _disY = 0;

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT 	ps;
	HDC		hdc;

	char str[128];

	switch (iMessage)
	{
	// 윈도우 창이 생성될때 딱 한번 호출되는 것
	case WM_CREATE:
	{
		_rc = RectMakeCenter(WINSIZEX / 2, WINSIZEY / 2, 100, 100);
	}
	break;

	// 그림을 그려주는 것
	case WM_PAINT:
	{
		hdc = BeginPaint(hWnd, &ps);

		sprintf_s(str, "마우스 X : %d, 마우스 Y : %d", _ptMouse.x, _ptMouse.y);
		TextOut(hdc, 20, 20, str, strlen(str));

		Rectangle(hdc, _rc);
		EndPaint(hWnd, &ps);
	}
	break;

	// 마우스 움직이면 여기서 메시지 발생
	case WM_MOUSEMOVE:
	{
		_ptMouse.x = LOWORD(lParam);
		_ptMouse.y = HIWORD(lParam);

		if (_flag == true)
		{
			_rc = RectMakeCenter(_ptMouse.x - _disX, _ptMouse.y - _disY, 100, 100);
		}
		InvalidateRect(_hWnd, NULL, true);
	}
	break;

	// 마우스 왼쪽 클릭 (눌려지고 있을때 여기)
	case WM_LBUTTONDOWN:
	{
		//마우스가 렉트안을 클릭했을 떄
		//if (_rc.left < _ptMouse.x && _ptMouse.x < _rc.right &&
		//	_rc.top < _ptMouse.y && _ptMouse.y < _rc.bottom)
		//{
		//	_flag = true;
		//	_disX = _ptMouse.x - (_rc.left + _rc.right) / 2;
		//	_disY = _ptMouse.y - (_rc.top + _rc.bottom) / 2;
		//}

		// 96번 라인과 같은 내용
		if (PtInRect(&_rc, _ptMouse))
		{
			_flag = true;
			_disX = _ptMouse.x - (_rc.left + _rc.right) / 2;
			_disY = _ptMouse.y - (_rc.top + _rc.bottom) / 2;
		}
	}
	break;

	// 마우스 왼쪽 눌렀다 뗏을 때
	case WM_LBUTTONUP:
	{
		_flag = false;
	}
	break;

	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_ESCAPE:
		{
			PostQuitMessage(0);
		}
		break;
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return (DefWindowProc(hWnd, iMessage, wParam, lParam));
}

void setWindowsSize(int x, int y, int width, int height)
{
	RECT winRect;
	winRect.left = 0;
	winRect.top = 0;
	winRect.right = width;
	winRect.bottom = height;

	AdjustWindowRect(&winRect, WINSTYLE, false);
	SetWindowPos(_hWnd, NULL, x, y, (winRect.right - winRect.left), (winRect.bottom - winRect.top), SWP_NOZORDER | SWP_NOMOVE);
}

 

 

 


 

 

 

어떻게 구현해야 할까?
마우스 왼쪽 버튼이 눌리면(LBUTTONDOWN) 그 위치에 있는 대상과 위치를 검사하여, 왼쪽 버튼이 눌려 있는 부분이 대상의 위치와 일치 한다면, 플래그를 On(true)시킨다.

마우스가 움직였을 때(MOUSEMOVE) 플래그의 상태가 On(true)라면 마우스의 x,y 위치를 대상의 x,y에 대입하면 된다.
그 후 왼쪽 버튼이 손에서 떨어지면(LBUTTONUP) 플래그를 Off(false)로 변경한다.

 

 

 


 

 


로직은?
1.사각형의 중점과 마우스 클릭한 좌표와의 x,y 거리를 구한다
2.마우스가 움직일때마다 사각형의 중점을 1에서 구한 x,y거리가 유지되도록 옮긴다

 

 

 


 

 

 

결과화면 & 심화학습

마우스가 윈도우 화면 바깥으로 나가지 않게 해보자

반응형