키보드 입력
키보드 입력이 발생하는 시점과 문자열을 출력해야 할 시점이 분리되어 있음
문자열을 계속 모아 두었다가 필요할 때 출력을 WM_PAINT에서 처리함
무효영역
: 윈도우의 일부분이 가려졌다가 나타나거나 최소화되었다가 복구시 무효영역이 발생
그때마다 운영체제가 WM_PAINT메세지를 발생시킴
강제로 윈도우의 작업영역을 무효화
BOOL InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);
1. hWnd
무효화의 대상이 되는 윈도우 나타냄
2. *lpRect
무효화할 사각영역을 지정
이 값이 NULL이면 윈도우의 전 영역이 무효화
화면이 깜빡거리지 않고 보기 좋게 하기위해서는 무효화할 사각영역을 정확하게 지정할 것
3.bErase
무효화되기 전에 배경을 모두 지운 후 다시 그릴 것인지 아니면 배경을 지우지 않고 그릴 것인지를 지정
이 값이 TRUE이면 배경을 지운 후 다시 그리고 FALSE이면 배경을 지우지 않은 채로 다시 그림
소스
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Key");
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
while(GetMessage(&Message, NULL, 0, 0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static TCHAR str[256];
int len;
switch(iMessage) {
case WM_CHAR:
if ((TCHAR)wParam == ' '){
str[0] = 0;
} else {
len = lstrlen(str);
str[len] = (TCHAR)wParam;
str[len+1] = 0;
}
//InvalidateRect(hWnd, NULL, FALSE);
return 0;
//len = lstrlen(str);
//str[len] = (TCHAR)wParam;
//str[len+1] = 0;
//InvalidateRect(hWnd, NULL, FALSE);
//return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 100, 100, str, lstrlen(str));
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
키보드 입력 메세지
문자키가 눌렸을 때 = WM_CHAR
몇 가지를 제외한 모든 키에 대해 키가 눌릴 때 = WM_KEYDOWN
키가 떨어질 때 = WM_KEYUP
wParam에 가상키코드가 전달됨
TranslateMessage(&Message)함수에서 WM_CHAR메세지 발생
발생조건 = WM_KEY DOWN + 문자키 입력
아래와 같이 어떤 키가 눌렸는지 조사
WM_SYSKEYDOWN, WM_SYSKEYUP, WM_SYSCHAR = Alt키와 함께 눌러지는 키보드 메세지
마우스 입력
메세지
버튼 |
누름 |
놓음 |
더블클릭 |
좌측 우측 중앙 |
WM_LBUTTONDOWN WM_RBUTTONDOWN WM_MBUTTONDOWN |
WM_LBUTTONUP WM_RBUTTONUP WM_MBUTTONUP |
WM_LBUTTONDBLCLK WM_RBUTTONDBLCLK WM_MBUTTONDBLCLK |
lParam => 마우스 버튼이 눌러진 좌표가 상위 워드에 y좌표, 하위 워드에 x좌표
좌표 값 검출 매크로 함수
LOWORD(lParam), HIWORD(lParam)
= x = y
wParam = 마우스 버튼 상태와 키보드 조합키(shift, ctrl)의 상태전달
WM_LBUTTONDWON = 누르고 있으면 계속 발생하는 게 아니라 눌렀을 때의 순간에만 메세지가 한번만 발생
WM_MOUSEMOVE = 마우스가 이동할 때마다 발생, 마우스 이동이 멈춘 x, y 좌표값 전달
WM_MOUSEWHEEL
WM_LBUTTONDBLCLK = 더블클릭, 사용 원할 시 WndClass.style = CS_DBLCLKS; 추가할 것
타이머
타이머 메세지 WM_TIMER(wParam : 타이머ID, lParam : 타이머 발생시 호출될 함수)
UINT SetTimer(HWND hWnd, UINT nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc)
= 윈도우 = 타이머의 번호
UINT uElapse = 타이머의 주기 설정 값에 따라 그 주기에 맞게 타이머 메세지 전달
= 1 / 1000 * uElapse초
TIMERPROC lpTimerFunc = 타이머 메시지가 발생할 때마다 호출될 함수 지정
BOOL KillTimer(HWND hWnd, UINT uIDEvent);
= 윈도우 = 타이머의 번호
SendMessage
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
= 윈도우 = 메세지 = 메세지에 따라 추가 정보가 달라짐
타이머를 여러개 설정하여 필요한 용도에 사용 가능
백그라운드 작업
WinMain함수에 무한루프를 작성하면 안됨
Setimer()함수와 WM_TIMER메세지를 이용하여 계속 지속되어야 할 작업을 작게 나눠서 처리할 것
콜백함수
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
hwnd = 타이머를 소유한 윈도우의 핸들
uMsg = WM_TIMER
idEvent = 타이머ID
dwTime = 윈도우즈가 실행된 후의 경과시간
콜백함수란(Callback Function)?
일반적으로 API함수들은 운영체제가 제공하며 프로그램에서는 이 함수들을 호출해서 운영체제의 서비스를 받는다
반면 콜백함수는 응용 프로그램이 제공하며 운영체제가 필요할 때 호출하는 함수
호출되는 방향이 거꾸로 되었기 때문에 콜백이라고 부름
일회용 타이머
Setimer()함수로 WM_TIMER메세지를 발생시키고
WndProc()함수 안에서 WM_TIMER에서 KillTimer()로 타이머를 한번만 사용하도록 함
윈도우 관리 메세지
생성 및 파괴
WinMain은 윈도우 생성 후, 파괴 후의 시점(프로그램 전역적인 초기/종료 처리)
WndProc은 윈도우 생성중, 파괴중(특정한 윈도우에 관련된 초기/종료 처리)
WM_CREATE(윈도우 생성)와 WM_DESTROY(윈도우 파괴)메세지
WM_DESTROY메세지 처리시 꼭 PostQuitMessage()함수를 호출해야 함
메인 윈도우는 응용프로그램이 처음 만드는 윈도우 자신이 파괴될 때 응용 프로그램을 종료해야 함
PostQuitMessage()함수는 WinMain()함수에 있는 메세지 루프를 종료시킴
작업영역
윈도우는 작업영역(Client Area)와 비작업영역(Non Client Area) 두 부분으로 구성됨
BOOL GetClientRect(HWND hWnd, LPRECT lpRect);
Client가 차지하고 있는 Rect를 얻기위한 함수
WM_SIZE
윈도우의 크기가 변경될 때마다 전달
lParam의 하위 워드에는 변경된 후의 윈도우 폭, 상위 워드에는 높이가 전달
wParam에서는 메세지가 발생한 이유를 나타내는 플래그를 전달
플래그 |
값 |
SIZE_MAXHIDE |
다른 윈도우가 최대화되어 이 윈도우가 가려졌음 |
SIZE_MAXIMIZED |
최대화 되었음 |
SIZE_MAXSHOW |
다른 윈도우가 원래 크기로 복구되어 이 윈도우가 드러남 |
SIZE_MINIMIZED |
최소화되었음 |
SIZE_RESTORED |
크기가 변경됨 |
WM_MOVE
윈도우의 위치가 변경될 때마다 보내짐
lParam의 하위 워드에 윈도우의 새 x좌표, 상위 워드에 윈도우의 새 y좌표가 전달