핵심 API로 배우는 윈도우 프로그래밍

핵심 API로 배우는 윈도우 프로그래밍 연습문제 2장 7, 8

딴짓거리 2022. 9. 22. 01:16

윈도우를 생성하는 WinMain 함수의 코드는 전부 중복이므로

WndProc 함수만 적는다.

 

작성자 본인이 공부 중 푼 문제로 모범답안이 아님을 밝힙니다.

 

7. 화면에 방향키 4개에 대한 사각형을 그린다. 키보드 방향키를 누르면 해당되는 사각형 면이 빨간색으로 변하고 글이 사라지며, 눌렀던 키를 높으면 사각형이 원래대로 돌아가고 글도 나타나도록 만들어보자.

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)	//메시지 처리 함수
{
	HDC				hdc;
	PAINTSTRUCT		ps;
	RECT			left_rt = { 50, 100, 100, 150 };
	RECT			right_rt = { 150, 100, 200, 150 };
	RECT			up_rt = { 100, 50, 150, 100 };
	RECT			down_rt = { 100, 150, 150, 200 };
	HBRUSH			hBrush, oldBrush;
	static TCHAR	str[10];
	switch (iMsg)
	{
	case WM_CREATE:
		break;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		//기본 틀
		Rectangle(hdc, 50, 100, 100, 150); // left
		DrawText(hdc, _T("좌측"), _tcslen(_T("좌측")), &left_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		Rectangle(hdc, 150, 100, 200, 150); // right
		DrawText(hdc, _T("우측"), _tcslen(_T("우측")), &right_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		Rectangle(hdc, 100, 50, 150, 100); // up
		DrawText(hdc, _T("상단"), _tcslen(_T("상단")), &up_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		Rectangle(hdc, 100, 150, 150, 200); // down
		DrawText(hdc, _T("하단"), _tcslen(_T("하단")), &down_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

		if (str[0] == VK_LEFT) // str에 저장되어있는 키 값에 따라 색칠
		{
			hBrush = CreateSolidBrush(RGB(255, 0, 0));
			oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
			Rectangle(hdc, 50, 100, 100, 150); // left
			SelectObject(hdc, oldBrush);
			DeleteObject(hBrush);
		}
		else if (str[0] == VK_RIGHT)
		{
		hBrush = CreateSolidBrush(RGB(255, 0, 0));
		oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
		Rectangle(hdc, 150, 100, 200, 150); // right
		SelectObject(hdc, oldBrush);
		DeleteObject(hBrush);
		}
		else if (str[0] == VK_UP)
		{
		hBrush = CreateSolidBrush(RGB(255, 0, 0));
		oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
		Rectangle(hdc, 100, 50, 150, 100); // up
		SelectObject(hdc, oldBrush);
		DeleteObject(hBrush);
		}
		else if (str[0] == VK_DOWN)
		{
		hBrush = CreateSolidBrush(RGB(255, 0, 0));
		oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
		Rectangle(hdc, 100, 150, 150, 200); // down
		SelectObject(hdc, oldBrush);
		DeleteObject(hBrush);
		}

		EndPaint(hwnd, &ps);
		break;

	case WM_KEYDOWN:		//키가 눌렸을 때
		hdc = GetDC(hwnd);
		str[0] = wParam;	//누른 키의 값을 저장
		InvalidateRgn(hwnd, NULL, TRUE);
		break;
	case WM_KEYUP:			//키를 땔 때
		hdc = GetDC(hwnd);
		str[0] = NULL;		//눌렀던 키의 값을 삭제
		InvalidateRgn(hwnd, NULL, TRUE);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}	//처리할 메시지만 case문에 나열
	return DefWindowProc(hwnd, iMsg, wParam, lParam);	//나머지는 커널이 처리
}

 

 

8. 화면에 사각형 글상자를 만들어보자. 사각형 왼쪽 상단에 캐럿이 나타나 문자의 입력을 기다린다. 글자를 입력하다가 글상자 경계를 만나면 캐럿이 다음 행으로 내려간다. enter 키를 입력해도 캐럿이 다음 행으로 내려간다. 글상자가 가득 차면 더 이상 입력을 받지 않고 사각형 모량과 캐럿이 사라진다.

 

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)	//메시지 처리 함수
{
	HDC				hdc;
	PAINTSTRUCT		ps;
	static TCHAR	str[1000][1000];
	static int		count, yPos;
	static SIZE		size;
	static bool		flag;
	switch (iMsg)
	{
	case WM_CREATE:
		CreateCaret(hwnd, NULL, 5, 15);
		ShowCaret(hwnd);
		flag = true;
		yPos = 0;
		count = 0;
		break;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		if(flag == true)
		{
			GetTextExtentPoint(hdc, str[yPos], _tcslen(str[yPos]), &size);
			Rectangle(hdc, 50, 50, 300, 300);
			for (int i = 0; i <= yPos; i++)
			{
				TextOut(hdc, 50, 50 + i * 20, str[i], _tcslen(str[i]));
			}
			SetCaretPos(size.cx + 50, yPos * 20 + 50);
		}
		else // 글상자를 벗어났다는 뜻이므로 캐럿을 삭제
		{
			HideCaret(hwnd);
			DestroyCaret();
		}
		EndPaint(hwnd, &ps);
		break;
	case WM_CHAR:
		hdc = GetDC(hwnd);
		if(yPos<=250/20-1) //글상자의 y축 범위
		{
			if (wParam == VK_BACK)
			{
				if (count == 0)
				{
					if (yPos > 0)
					{
						yPos--;
						count = _tcslen(str[yPos]);
					}
				}
				else
				{
					count--;
					str[yPos][count] = NULL;
				}
			}
			else if (wParam == VK_RETURN)
			{
				str[yPos][count] = '\0';
				yPos++;
				count = 0;
			}
			else
			{
				if (size.cx + 5 >= 250) // 글상자의 x축 범위
				{
					str[yPos][count] = '\0';
					yPos++;
					count = 0;
				}
				else
				{
					str[yPos][count++] = wParam;
					str[yPos][count] = NULL;
				}
				
				
			}
		}
		else // 글상자 범위를 벗어나면 flag를 false 해줌
		{
			flag = false;
		}
		InvalidateRgn(hwnd, NULL, TRUE);
		break;
	case WM_DESTROY:
		HideCaret(hwnd);
		DestroyCaret();
		PostQuitMessage(0);
		break;
	}	//처리할 메시지만 case문에 나열
	return DefWindowProc(hwnd, iMsg, wParam, lParam);	//나머지는 커널이 처리
}

글상자는 픽셀단위로 그려져 있으므로 글상자를 벗어났다는 판단은 픽셀단위로 결정해야한다.

다행이도 캐럿을 생성하기 위해 항상 문자열의 길이를 측정하고 있으므로 이를 적절히 이용해준다.

 

아래로 범위를 초과하면 화면이 깨끗해진다.

8번 문제는 캐럿의 위치라던가 글상자의 범위를 가져오는것이나 약간의 생각이 필요했다.

 

현재 9번을 풀고 있으나 windows.h 기본함수를 이용한 문자열의 처리에 엄청난 어려움을 겪고 있다.

풀수 있을지는 모르겠지만 풀게된다면 정리해서 올릴 예정이다.