핵심 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 기본함수를 이용한 문자열의 처리에 엄청난 어려움을 겪고 있다.
풀수 있을지는 모르겠지만 풀게된다면 정리해서 올릴 예정이다.