WM_PAINT

인수

wParam : 그리기에 사용할 DC 핸들이 전달되며 이 값이 NULL일 경우 디폴트 DC에 그려야 한다. 이 인수로 전달되는 DC는 일부 공통 컨트롤에 의해 사용될 뿐이며 일반적인 목적으로는 사용하지 않는 것이 안전하다. 이 DC 핸들보다는 BeginPaint 함수가 리턴하는 DC 핸들을 사용하는 것이 좋다.

설명

윈도우의 작업 영역중 일부가 무효화되어 있을 때 시스템이 이 메시지를 큐에 넣어준다. 다음과 같은 경우에 무효 영역이 설정되며 이때마다 WM_PAINT메시지가 전달된다.

① 윈도우가 처음 생성되었을 때
② 윈도우의 위치가 이동되었을 때
③ 윈도우의 크기가 변경되었을 때. 최대, 최소화되었을 때
④ 다른 윈도우에 가려져 있다가 드러날 때
⑤ 스크롤 될 때

또는 응용 프로그램 내부에서 InvalidateRect 함수 호출에 의해 강제로 무효 영역을 설정할 수 있다. 윈도우는 이 메시지를 받았을 때 작업 영역 전체 또는 무효화된 부분을 다시 그려야 한다. 운영체제는 윈도우의 작업영역을 복구해 주지 않는 대신에 무효화될 때 이 메시지를 보내 줌으로써 윈도우에게 다시 그려야 할 시점을 알려 주기만 한다. 따라서 윈도우는 자신의 작업영역에 출력할 수 있는 모든 자료를 완벽하게 저장해 두어야 한다.

WM_PAINT 메시지는 모든 메시지 중에 우선 순위가 가장 늦다. GetMessage 함수는 메시지 큐에 WM_PAINT가 있더라도 다른 메시지가 대기중이면 이 메시지를 먼저 처리한다. WM_PAINT 메시지는 큐에 대기중인 다른 메시지가 없을 때, 그리고 무효 영역이 존재할 때만 윈도우 프로시저로 보내진다. 또한 WM_PAINT 메시지는 한번에 하나만 메시지 큐에 들어갈 수 있다. 만약 무효영역이 생겼을 때 WM_PAINT 메시지가 이미 메시지 큐에 있으면 기존의 무효영역과 새 무효영역의 합집합으로 새로운 무효영역이 설정된다.

윈도우가 이 메시지를 처리하지 않으면 이 메시지는 DefWindowProc 함수가 처리한다. 이 함수는 무효영역을 모두 유효화화기만 하며 다시 그리기는 하지 않는다. 만약 비작업 영역도 그려져야 한다면 WM_NCPAINT 메시지를 전달하며 또한 배경을 지워야 한다면 WM_ERASEBKGND 메시지를 전달한다.

WM_PAINT 메시지에서 그리기를 할 때는 BeginPaint 함수와 EndPaint 함수를 사용해야 한다. 이 두 함수는 WM_PAINT내에서만 사용되며 다시 그려야 할 영역에 대한 정확한 좌표를 조사하며 무효영역을 유효화하고 캐럿을 숨기거나 배경을 지우는 등의 꼭 필요한 동작을 한다.

리턴

이 메시지를 처리했으면 0을 리턴한다.

예제

예제 1

다음 예제는 문자열 변수 g_Str에 정의되어 있는 문자열을 WM_PAINT에서 화면으로 출력한다. 이 윈도우가 가려지거나 최소화되더라도 무효화될 때마다 WM_PAINT에서 다시 출력하므로 항상 이 문자열이 보인다.

char g_Str[]="이 문자열은 항상 보인다";
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch(iMessage) {
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,10,g_Str,lstrlen(g_Str));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

만약 프로그램 내부에서 이 문자열을 편집하거나 변경할 경우 InvalidateRect 함수로 작업영역을 무효화하여 다시 출력하도록 해야 한다.

예제 2

다음 예제는 화면의 특정한 좌표에 도형을 그리고 키보드로 이 도형의 위치를 옮긴다. 전역 변수 x,y에 도형의 현재 위치가 저장되어 있으며 WM_PAINT에서는 항상 이 위치에 도형을 출력한다. 도형의 위치를 변경하는 WM_KEYDOWN에서는 x,y값을 바꾼 후 작업 영역만 무효화할 뿐 직접 도형을 옮기지는 않는다.

int x,y;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch(iMessage) {
	case WM_CREATE:
		x=100;
		y=100;
		return 0;
	case WM_KEYDOWN:
		switch(wParam) {
		case VK_LEFT:
			x-=5;
			InvalidateRect(hWnd,NULL,TRUE);
			break;
		case VK_RIGHT:
			x+=5;
			InvalidateRect(hWnd,NULL,TRUE);
			break;
		case VK_UP:
			y-=5;
			InvalidateRect(hWnd,NULL,TRUE);
			break;
		case VK_DOWN:
			y+=5;
			InvalidateRect(hWnd,NULL,TRUE);
			break;
		}
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		Rectangle(hdc,x,y,x+100,y+100);
		SelectObject(hdc,GetStockObject(GRAY_BRUSH));
		Ellipse(hdc,x+10,y+10,x+90,y+90);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

실행중의 모습은 다음과 같다. 이 예제와 같이 화면이 변경되는 동작을 한 경우는 직접 화면을 다시 그리지 않고 내부 정보만을 변경한 후 작업영역을 무효화하여 WM_PAINT에서 다시 그리도록 해야 한다.

최대한 작은 영역만을 그리고자 할 경우는 PAINTSTRUCT 구조체를 적절히 활용해야 한다.

플랫폼

95이상

참조

12장


written by http://www.winapi.co.kr