목표
Win32 API를 활용해 작업 영역의 크기를 알아보도록 하겠습니다.
목차 클릭하면 해당 목차로 이동합니다.
2. GetClientRect 함수를 통해 작업 영역 얻기
개요
기존 프로젝트를 실행하고 윈도우의 크기를 변경하면 사이즈는 바뀌지만, 내용은 그대로 있는 것을 알 수 있습니다. 사이즈를 줄이면 내용이 안보이는 상황입니다. 대부분의 웹사이트를 접속하면 브라우저의 크기를 변경하면 크기에 맞게 내용이 이동하는 것을 보신 적이 있을 것입니다. 이는 크기가 바뀌어도 사용자가 내용을 확인할 수 있도록 반응형 웹사이트로 만든 것입니다. Win32 API로 만든 윈도우도 이와 같은 기능을 구현할 수 있습니다.
1. 작업 영역(Client Area)
우선 작업 영역에 대해서 알아보도록 하겠습니다. 작업 영역이라 함은 말 그대로 윈도우가 차지하고 있는 작업을 하고 있는 영역입니다. Window에서 제공하는 대표적인 응용 프로그램인 메모장을 확인해보겠습니다.
빨간색으로 표시된 곳이 작업 영역입니다. 글을 쓰고, 지울 수 있는 영역입니다. 그 위에는 엑셀레이터 등이 있습니다. 빨간색 사각형의 왼쪽 위 꼭짓점이 원점입니다. 이 영역을 알고 있으면 사이즈에 맞춰 알맞은 기능을 구현할 수 있습니다. 예를 들면, 화면의 가운데에 글씨를 출력하거나 화면의 위에서 아래로 내려가는 기능을 구현할 수 있습니다.
1-1 GetClientRect 함수
작업 영역을 얻기 위한 함수는 GetClientRect 함수입니다. 이 함수의 원형은 다음과 같습니다.
BOOL GetClientRect(HWND hWnd, LPRECT lpRect);
작업 영역을 알고자 하는 윈도우의 핸들과 작업 영역이 저장될 사각형의 주소 정보가 인수로 들어갑니다. hWnd가 갖고 있는 윈도우의 작업 영역이 lpRect에 저장되는 것입니다. 타이머와 같이 함수가 사용되는 위치에 따라서 알맞게 활용될 수 있습니다. 개발자의 의도에 따라 다르겠지만, 크게 다음 세 개의 메세지에서 활용될 수 있습니다.
- WM_CREATE
- WM_SIZE
- WM_PAINT
WM_CREATE는 프로그램이 실행될 때 최초 발생하는 메세지입니다.
WM_PAINT는 화면에 변화가 생겼거나 무효 영역(InvalidateRect 함수 등)이 생기면 발생하는 메세지입니다.
WM_SIZE는 윈도우의 크기가 변화하면 발생하는 메세지입니다. 우리가 윈도우의 끝 부분에 마우스를 올리면 마우스가 화살표로 변하게 됩니다. 이 때, 클릭하고 움직이면 윈도우의 크기가 변화합니다. 이 때 WM_SIZE 메세지가 발생하는 것입니다. 각각의 상황에서 GetClientRect 함수를 사용하고 결과를 확인해보도록 하겠습니다.
2. GetClientRect 함수를 통해 작업 영역 얻기
Client 프로젝트
이번 프로젝트는 화면의 중앙에 "Center String"을 출력합니다. 원활한 실습을 위하여 윈도우의 크기를 변경하겠습니다. 윈도우는 WinMain에서 CreateWindow 함수를 이용해 만들어집니다.
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, (HMENU)NULL, hInstance, NULL);
기존에는 위와 같이 두번째 줄을 CW_USEDEFAULT 를 넣었습니다. 이는, 운영체제가 판단해 적당한 크기의 윈도우를 생성하는 것입니다. 각 인수는 첫 번째부터 X, Y, Width, height 입니다. 자세한 내용은 다음 링크를 참고해주세요.
참고 - [Windows API] Win32 API의 기본구조, WinMain-(2)
이번 프로젝트는 300,300,250,250으로 조금 작게 생성해서 진행하겠습니다.
2-1 WM_CREATE
프로젝트 생성시 작업 영역을 얻어 문자열을 출력해보겠습니다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static RECT rt;
switch (iMessage) {
case WM_CREATE:
GetClientRect(hWnd, &rt);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SetTextAlign(hdc, TA_CENTER);
TextOut(hdc, rt.right / 2, rt.bottom / 2, _T("Center String"), 13);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
위와 같이 WM_CREATE에서 GetClientRect 함수를 사용해서 작업 영역을 얻은 뒤, WM_PAINT에서 화면에 문자열을 출력하고 있습니다. 윈도우가 처음 실행되면 WM_CREATE 메세지가 발생하고, 윈도우를 화면에 띄우기 위해서 WM_PAINT 메세지를 자동으로 발생하기 때문에, InvalidateRect 함수를 사용하지 않아도 WM_PAINT 메세지가 발생합니다.
결과는 다음과 같습니다.
보시는 것처럼, 최초에는 중앙에 문자열이 정상적으로 출력되었지만, 윈도우의 크기가 변경돼도 문자열의 위치가 변경되지 않습니다. 따라서, 크기가 작아지면 문자열이 일부 가려지는 것을 알 수 있습니다. 윈도우의 크기가 바뀌어도 얻은 영역의 정보가 바뀌지 않기 때문입니다.
2-2 WM_SIZE
윈도우의 크기가 변경되면 WM_SIZE 메세지가 발생합니다. 잠깐 생각해보면, 윈도우의 크기가 변경될 때 작업 영역의 정보를 얻는 것이 가장 이상적입니다. 한 번 확인해보도록 하겠습니다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static RECT rt;
switch (iMessage) {
case WM_SIZE:
GetClientRect(hWnd, &rt);
InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SetTextAlign(hdc, TA_CENTER);
TextOut(hdc, rt.right / 2, rt.bottom / 2, _T("Center String"), 13);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
윈도우의 크기가 변화함에 따라서 문자열의 위치도 이동하는 것을 볼 수 있습니다. 최소한의 크기 아래로는 줄어들지 않네요. 크기가 변화할 때마다, WM_SIZE 메세지가 발생하면서 작업 영역을 최신화하기 때문에 그 때마다 문자열을 올바른 위치에 출력할 수 있는 것입니다.
결과는 다음과 같습니다.
2-3 WM_PAINT
사실, 위에서 InvalidateRect 함수를 사용한 것은 보여주기 위함입니다. WM_SIZE가 발생하면 화면의 크기가 변화한 것이므로 WM_PAINT가 자동으로 발생하게 됩니다. 따라서 결과는 WM_SIZE와 동일합니다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static RECT rt;
switch (iMessage) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SetTextAlign(hdc, TA_CENTER);
GetClientRect(hWnd, &rt);
TextOut(hdc, rt.right / 2, rt.bottom / 2, _T("Center String"), 13);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
결과는 WM_SIZE 메세지에서 사용한 것과 동일합니다.
정리
GetClientRect 함수를 통해서 작업 영역 정보를 흭득할 수 있습니다. 가운데 뿐만 아니라, 화면의 특정 위치에 표시하는 등 다양한 상황에서 활용될 수 있는 유용한 함수입니다.
'개발 > Win32 API Programming' 카테고리의 다른 글
[Windows API] Win32 API의 펜과 브러쉬, Old의 의미 (0) | 2022.02.08 |
---|---|
[Windows API] Win32 API의 그래픽, GDI와 스톡 오브젝트(Stock Object) (0) | 2022.02.08 |
[Windows API] Win32 API의 백그라운드 작업과 콜백 함수 (0) | 2022.01.20 |
[Windows API] Win32 API를 활용해 시계, 일회용 타이머 만들기 - (2) (0) | 2022.01.18 |
[Windows API] Win32 API의 타이머를 활용해 시계 만들기 - (1) (0) | 2022.01.11 |