학원/경일게임아카데미

22. 열네번째 수업과제 [윈도우 탐색기 구현]

셩잇님 2022. 12. 23. 12:27
반응형

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

 

 

 


 

 

 

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

과제1 - 아이콘 드래그 앤 드롭
과제2 - 윈도우 탐색기 구현

이하 과제 2.

#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;		// 마우스 클릭 유무
int _sect;		// 분면 정의
int _disX, _disY;	// 중점에서 마우스 클릭좌표 거리를 뺀 값을 구하기 위한 변수

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)
		{
			switch (_sect)
			{
			case 1:
				_rc.left = _ptMouse.x - _disX;
				_rc.top = _ptMouse.y - _disY;
				break;
			case 2:
				_rc.right = _ptMouse.x - _disX;
				_rc.top = _ptMouse.y - _disY;
				break;
			case 3:
				_rc.left = _ptMouse.x - _disX;
				_rc.bottom = _ptMouse.y - _disY;
				break;
			case 4:
				_rc.right = _ptMouse.x - _disX;
				_rc.bottom = _ptMouse.y - _disY;
				break;
			}
		}
		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;

			int centerX = (_rc.left + _rc.right) / 2;
			int centerY = (_rc.top + _rc.bottom) / 2;

			/* 사분면
			ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
			|		  |		   |
			|		  |		   |
			|	 1	  |	  2	   |
			|		  |		   |
			|		  |		   |
			ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
			|		  |		   |
			|		  |		   |
			|	 3	  |	  4	   |
			|		  |		   |
			|		  |		   |
			ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
			*/

			// 1
			if (_ptMouse.x < centerX && _ptMouse.y < centerY)
			{
				_sect = 1;
				_disX = LOWORD(lParam) - _rc.left;
				_disY = HIWORD(lParam) - _rc.top;
			}
			// 2
			if (_ptMouse.x > centerX && _ptMouse.y < centerY)
			{
				_sect = 2;
				_disX = LOWORD(lParam) - _rc.right;
				_disY = HIWORD(lParam) - _rc.top;
			}
			// 3 
			if (_ptMouse.x < centerX && _ptMouse.y > centerY)
			{
				_sect = 3;
				_disX = LOWORD(lParam) - _rc.left;
				_disY = HIWORD(lParam) - _rc.bottom;
			}
			// 4
			if (_ptMouse.x > centerX && _ptMouse.y > centerY)
			{
				_sect = 3;
				_disX = LOWORD(lParam) - _rc.right;
				_disY = HIWORD(lParam) - _rc.bottom;
			}
		}
	}
	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);
}

 

어떻게 구현해야 할까?
마우스가 어디를 클릭했는지에 따라 4분면을 기준으로 구현한다.

 



로직은?
마우스 클릭한 지점이 어느 분면인지 확인한다.
분면을 클릭한 이후 중점을 기준으로 거리(DISTANCE)를 구해준다.
분면에 따라서 마우스 x좌표는 left, right y좌표는 top, bottom과 일치시킨다.

 


 

결과화면

반응형