«   2018/09   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
Statistics Graph
관리 메뉴

언제나 휴일

2.1 WM_PAINT 메시지 [Windows API] 본문

프로그래밍 기술/Windows API

2.1 WM_PAINT 메시지 [Windows API]

언제나 휴일 언제나휴일 2016.04.07 23:19

2.1 WM_PAINT 메시지

윈도우에 다른 윈도우에 의해 가려졌다가 보여지거나 최소화 후에 최대화를 하는 등의 작업을 수행하면 다시 그려주어야 하는 영역이 생깁니다. 윈도우즈 운영체제에서는 다른 창에 의해 가려지는 영역을 클리핑 영역으로 기억해 두었다가 해당 영역이 다시 보여지면 그 부분을 포함하는 최소한의 사각 영역을 무효화 영역이 발생한 것으로 처리합니다. 이 때 발생하는 윈도우 메시지가 WM_PAINT입니다.

그런데 윈도우즈 프로그램에서 무효화 영역이 생긴다고 바로 WM_PAINT 메시지를 발생하여 처리하는 것은 아닙니다. 일반적으로 윈도우즈 프로그램에서 그리기 작업은 다른 작업들보다 처리 우선순위가 낮습니다. 따라서 응용 메시지 큐에 처리할 윈도우 메시지가 없고 무효화 영역이 있을 때 WM_PAINT 메시지를 만들어 집니다. 만약 무효화 영역이 있지만 처리할 윈도우 메시지가 응용 메시지 큐에 남아있다면 응용 메시지 큐에 남아있는 메시지가 사라질 때까지 WM_PAINT 메시지는 만들어지지 않습니다. 이런 상태에서 다시 무효화 영역이 생기면 기존 무효화 영역과 합산하여 동시에 WM_PAINT가 두 번 발생하지 않게 처리하고 있습니다.  

WM_PAINT 메시지 처리기에서는 무효화 영역을 계산하고 DC를 발급받는 것부터 시작합니다. 그리고 그리기 작업을 마친 후에 DC를 해제하고 무효화 영역을 유효화 영역으로 변경해 주어야 합니다. 만약 그리기 작업을 마친 후에 무효화 영역을 유효화 영역으로 변경하지 않으면 처리할 메시지가 없을 때 WM_PAINT가 계속 발생하여 시스템 성능이 떨어집니다.

 

HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint);

BOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint);

Windows API에서는 무효화 영역을 계산하고 DC를 발급받는 것을 한꺼번에 처리하는 BeginPaint 함수를 제공하고 있습니다. 그리고 DC를 해제하고 무효화 영역을 유효화 영역으로 변경하는 것은 EndPaint 함수를 호출하면 내부에서 모든 처리를 해 줍니다

 

struct PAINTSTRUCT {

    HDC         hdc;

    BOOL        fErase;

    RECT        rcPaint;

    BOOL        fRestore;

    BOOL        fIncUpdate;

    BYTE        rgbReserved[32];

};

BeginPaint EndPaint에 사용하는 PAINTSTRUCT 구조체의 rcPaint에서 다시 그려줄 영역을 계산한 값이예요.

 

WM_PAINT 처리기에서는 BeginPaint 함수를 호출한 후에 그리기 작업을 수행하고 EndPaint 함수를 호출하여 작업을 마무리하세요.

void OnDraw(HWND hWnd,HDC hdc)

{

     //그리기 작업

}

void OnPaint(HWND hWnd)

{

    PAINTSTRUCT ps;

    BeginPaint(hWnd,&ps);//무효화 영역 계산 및 DC 핸들 발급

    OnDraw(hWnd,ps.hdc);  

    EndPaint(hWnd,&ps);//발급받은 DC 소멸 및 무효화 영역을 유효화 영역으로 갱신

}

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

    switch(iMessage)

    {

    case WM_PAINT: OnPaint(hWnd); return 0;

    ...중략...

    }

    return DefWindowProc(hWnd,iMessage,wParam,lParam);

}

 

BOOL WINAPI InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);

그리고 프로그램 방식으로 무효화 영역을 만들어 다시 그리게 할 때는 Invalidate로 시작하는 함수를 호출합니다. 가장 많이 사용하는 함수는 InvalidateRect입니다.

 

InvalidateRect의 두 번째 인자는 다시 그려줄 사각 영역을 설정한 변수의 주소입니다. 그리고 세 번째 인자는 배경을 다시 그릴지 여부입니다. 만약 윈도우 전체 화면을 다시 그리게 하려면 두 번째 인자에 0을 전달하세요. 만약 특정 영역만 다시 그리게 할 때는 사각 영역을 계산하여 전달하세요. 전체 영역을 다시 그리면 화면이 깜빡거리는 현상이 발생할 수 있습니다.

 

보다 자세한 사용은 그리기 개체와 그리기 작업에 관한 함수를 다루면서 구체적으로 다루기로 할게요.

2 Comments
댓글쓰기 폼