자료 저장소

# 그리기 메시지

BeginPaint가 하는 일 중 다섯 번째가 WM_NCPAINT 메시지와 WM_ERASEBKGND 메시지를 보내는 것이다.

WM_NCPAINT 메시지는 비작업영역이 그려져야 할때 운영체제가 보내는 메시지이며 응용프로그램 이 메시지를
받았을 때 타이틀 바, 경계선, 시스템 메뉴 등을 그려야 한다.
NCPAINT의 접두어 NC는 Non Clien Area 즉, 비작업영역이란 뜻이다.
이 메시지는 직접 처리하지 않아도 DefWindowProc에서 처리하며 대부분의 응용 프로그램이 이 메시지를 처리
하지 않는다.

WM_ERASEBKGND 메시지는 윈도우 클래스에 등록된 배경 브러시로 작업영역의 배경을 지우는 역할을 한다.
윈도우 클래스 정의문을 보면 배경 브러시를 보통 흰색이나 COLOR_WINDOW 시스템 색상으로 지정한다.
WM_ERASEBKGND 메시지는 배경 브러시가 등록되어 있을 경우 이 브러시로 배경을 칠하는데 이는 곧 배경을
지우는 것이다. 새로운 그림을 그리기 위해서는 전에 그려져 있던 그림을 지워야 하는데 이 메시지가 그 일을
한다. 이 메시지도 DefWindowProc으로 그냥 보내주기만 하면된다.

이 메시지를 직접 처리해서 배경을 바꾸거나 원하는 비트맵을 그릴 수 있다.


# GetDC

대부분의 그리기 동작은 WM_PAINT 메시지 처리 루틴에서 수행하는 것이 정상적이다. 그러나 특수한 경우에
WM_PAINT 메시지 밖에서 그리기를 하는 것이 더 효율적이거나 즉시 그리기를 해야만 할 때가 있다.
WM_PAINT 밖에서 그리기를 할 때는 GetDC 함수로 DC 핸들을 얻으며 그리기가 끝나면 ReleaseDC 함수로
DC 핸들을 해제한다.

HDC GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags);

위 함수는 GetDC의 확장 함수인데 클리핑 영역 지정에 대한 옵션을 지정할 수 있다. 두 번째 인수로 가시영역과
조합될 클리핑 리전을 지정한다. flags에 DCX_INTERSECTRGN이나 DCX_EXCLUDEGRN이 지정되어 있으면
이 인수로 전달된 클리핑 리전은 운영체제가 소유하며 사용 후 자동으로 파괴되므로 응용 프로그램은 이 리전을
더 이상 사용해서는 안된다. 세번째 인수는 DC를 생성할 방법을 지정하는 여러가지 플래그의 조합이다.

MSDN : http://msdn.microsoft.com/en-us/library/dd144873(v=VS.85).aspx

HWND WindowFromDc(HDC hdc);

이 함수는 GetDC와 반대되는 개념의 함수이며 인수로 DC를 전달하면 이 DC가 그리는 윈도우의 핸들을 구한다.
DC를 전달받은 그리기 함수가 윈도우에 대해 어떤 작업을 하고 싶을 때 관련 윈도우의 핸들을 구한다.


# 그리기 정보의 보관

윈도우즈용 프로그램의 그리기는 모두 WM_PAINT 메시지에 모아져야 하며 언제든지 WM_PAINT메시지가
전달되면 원래의 모습대로 감쪽같이 다시 그릴 준비가 되어 있어야 한다.

[그리기 정보를 배열에 저장하는 예제]
// 그려지는 선의 정보를 담는 구조체 배열
struct {
int x,y;
BOOL Move;
} Line[10000];
int index=0;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int i;
static BOOL bNowDraw=FALSE;
switch (iMessage) {
// 시작점의 위치를 배열에 기록해 둔다.
case WM_LBUTTONDOWN:
bNowDraw=TRUE;
Line[index].x=LOWORD(lParam);
Line[index].y=HIWORD(lParam);
Line[index].Move=TRUE;
index++;
return0;
// 다음 마우스 이동점까지 선을 그리고 배열상에 기록한다.
case WM_MOUSEMOVE:
if (bNowDraw==TRUE) {
hdc=GetDC(hWnd);
MoveToEx(hdc,Line[index-1].x,Line[index-1].y,NULL);
Line[index].x=LOWORD(lParam);
Line[index].y=HIWORD(lParam);
Line[index].Move=FALSE;
LineTo(hdc,Line[index].x,Line[index].y);
index++;
ReleaseDC(hWnd,hdc);
}
return0;
// 그리기를 종료한다.
case WM_LBUTTONUP:
bNowDraw=FALSE;
return0;
// 화면을 지우고 다시 그리며 배열의 인덱스를 리셋하여 다시 기록하도록 한다.
case WM_RBUTTONDOWN:
index=0;
InvalidateRect(hWnd, NULL, TRUE);
return0;
// 배열의 정보를 읽어 화면을 복구한다.
case WM_PAINT:
hdc=BeginPaint(hWnd, &ps);
for (i=0;i<index;i++) {
if (Line[i].Move == TRUE) {
MoveToEx(hdc,Line[i].x, Line[i].y, NULL);
} else {
LineTo(hdc,Line[i].x, Line[i].y);
}
}
EndPaint(hWnd, &ps);
return0;
case WM_DESTROY:
PostQuitMessage(0);
return0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
10000개까지 선을 기억할 수 있는 구조체 배열 Line을 선언하고 마우스가 이동할 때마다 이 구조체에 마우스의
좌표를 기록하였다. 이 정보를 모아서 저장 해두었으므로 파일 입출력 기능만 더해지면 저장도 가능하다.
위 예제를 연결리스트나 동적배열을 사용하고 예외처리를 한다면 좀 더 완벽한 프로그램이 된다.


# 비트맵에 저장하기

[메모리 비트맵에 그림을 저장하는 예제]
HBITMAP hbit; 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc, hMemDC;
HBITMAP OldBitmap;
staticint x;
staticint y;
static BOOL bNowDraw=FALSE;
PAINTSTRUCT ps;
switch (iMessage) {
// 1024*768 크기의 메모리 비트맵을 만들고 초기화한다.
case WM_CREATE:
hdc=GetDC(hWnd);
hbit=CreateCompatibleBitmap(hdc, 1024,768);
hMemDC=CreateCompatibleDC(hdc);
OldBitmap=(HBITMAP)SelectObject(hMemDC, hbit);
SelectObject(hMemDC, GetStockObject(WHITE_PEN));
Rectangle(hMemDC, 0,0,1024,768);
SelectObject(hMemDC, OldBitmap);
DeleteDC(hMemDC);
ReleaseDC(hWnd, hdc);
return0;
// 그리기를 시작한다.
case WM_LBUTTONDOWN:
x=LOWORD(lParam);
y=HIWORD(lParam);
bNowDraw=TRUE;
return0;
// 화면과 메모리 비트맵으로 동시에 출력한다.
case WM_MOUSEMOVE:
if (bNowDraw==TRUE) {
hdc=GetDC(hWnd);
hMemDC=CreateCompatibleDC(hdc);
OldBitmap=(HBITMAP)SelectObject(hMemDC, hbit);
MoveToEx(hdc,x,y,NULL);
MoveToEx(hMemDC,x,y,NULL);
x=LOWORD(lParam);
y=HIWORD(lParam);
LineTo(hdc,x,y);
LineTo(hMemDC,x,y);
SelectObject(hMemDC, OldBitmap);
DeleteDC(hMemDC);
ReleaseDC(hWnd,hdc);
}
return0;
case WM_LBUTTONUP:
bNowDraw=FALSE;
return0;
// 메모리 비트맵에 저장된 그림을 화면으로 고속 전송한다.
case WM_PAINT:
hdc=BeginPaint(hWnd, &ps);
hMemDC=CreateCompatibleDC(hdc);
OldBitmap=(HBITMAP)SelectObject(hMemDC, hbit);
BitBlt(hdc,0,0,1024,768,hMemDC,0,0,SRCCOPY);
SelectObject(hMemDC, OldBitmap);
DeleteDC(hMemDC);
EndPaint(hWnd, &ps);
return0;
case WM_DESTROY:
DeleteObject(hbit);
PostQuitMessage(0);
return0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

댓글 로드 중…

최근에 게시된 글