< 무효영역 >

 

무효영역이란 화면의 일부가 변경되어 다시 그려져야 할 부분을 말한다.

만약 윈도우 전체가 다 변경되는 경우라면 무효영역은 작업영역과 동일하지만 윈도우의 일부분만 변경되었다면 변경된 부분만

무효영역이 된다.

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
BOOL bRect = TRUE;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rt;
    int i;
 
    switch(iMessage) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
 
        for (i=0; i<1024; i+=5) {
            MoveToEx(hdc, 0, i, NULL);
            LineTo(hdc, 1280, i);
        }
        
        for (i=0; i<1280; i+=5) {
            MoveToEx(hdc, i, 0NULL);
            LineTo(hdc, i, 1024);
        }
 
        if (bRect) {
            Rectangle(hdc, 1010200200);
        }
        else {
            Ellipse(hdc, 1010200200);
        }
 
        EndPaint(hWnd, &ps);
        return 0;
    case WM_LBUTTONDOWN:
        bRect = !bRect;
        SetRect(&rt, 10,10,200,200);
        InvalidateRect(hWnd, &rt, TRUE);
        return 0;
    }
 
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

상기 코드는 화면 전체를 다 그리지 않고 다시 그릴 필요가 있는 영역만 무효화 시켜 다시 그리는 기능을 가진 코드이다.

그렇기 때문에 화면 깜빡임이 없다. 그러나 실제로 그려야 할 부분보다 무효영역을 좁게 설정한다면 원하지 않는 그림이

출력되기 때문에 무효영역은 정확하게 계산해야 한다.

 

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

lpRect에 RECT의 주소값을 넘기면 RECT 사이즈만큼만 무효영역이 되어 해당 부분만 다시 그린다.

 

< 클리핑 영역 >

 

무효영역은 위에서 말했듯이 다시 그려져야 할 부분이다. 그런데 운영체제가 실제 그리기에 사용하는 영역은 무효영역이

아니라 클리핑 영역이다.

클리핑 영역은 무효영역(다시 그려져야 하는 영역) 중에서도 화면에 보이는 가시 영역을 말한다.

 

동영상 재생기의 경우에는 영상이 진행되는 동안 계속 무효화되면서 다시 그려진다. 그런데 동영상 재생기 위에 다른 윈도우가

올라가져 있어 영상을 일정 부분 가리고 있다면, 가려진 부분을 제외하고 화면에 보여지는 영상 부분이 클리핑 영역이 되는 것이다.

 

< 윈도우 스타일 >

 

화면에 버튼이나 에디트 박스 등의 여러 차일드 컨트롤이 있을 것이다. 만약 화면에 어떤 도형을 그린다고 할 때, 도형이 그려지는

영역과 컨트롤이 있는 영역이 겹친다면 컨트롤 영역에는 도형이 그려지지 않게 해야한다.

이러한 기능을 원한다면 윈도우 스타일에 WS_CLIPCHILDREN을 추가함으로써 차일드의 영역을 클리핑 영역에서 제외하여 차일드가

불필요하게 다시 그려지지 않도록 하면 된다.

 

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
31
32
33
34
35
36
37
38
39
40
41
BOOL bRect = TRUE;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HPEN hPen, OldPen;
    HBRUSH OldBrush;
 
    switch(iMessage) {
    case WM_CREATE:
        CreateWindow(TEXT("button"), TEXT("Child Button"),WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
            5050200100, hWnd, (HMENU)0, g_hInst, NULL);
        CreateWindow(TEXT("listbox"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY, 
            50200200100, hWnd, (HMENU)1, g_hInst, NULL);
        CreateWindow(TEXT("edit"), TEXT("에디트 컨트롤입니다."),WS_CHILD | WS_VISIBLE | WS_BORDER, 
            30012020080, hWnd, (HMENU)2, g_hInst, NULL);
        hWndMain = hWnd;
        return 0;
    case WM_LBUTTONDOWN:
        hdc = GetDC(hWnd);
        OldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
        hPen = CreatePen(PS_SOLID, 4, RGB(255,0,0));
        OldPen = (HPEN)SelectObject(hdc, hPen);
        
        Ellipse(hdc, LOWORD(lParam)-50, HIWORD(lParam)-40, LOWORD(lParam)+50, HIWORD(lParam)+40);
 
        DeleteObject(SelectObject(hdc, OldPen));
        SelectObject(hdc, OldBrush);
        ReleaseDC(hWnd, hdc);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
 
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

해당 코드만 가지고 실행한다면 버튼 클릭 시 차일드 컨트롤 위에도 타원이 그려질 것이다.

위에서 설명한 것과 같이 윈도우 스타일에 WS_CHILDREN을 추가한 후에 다시 실행하면 컨트롤 위에는 타원이 그려지지 않는다.

 

1
2
    hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT,CW_USEDEFAULT,
        CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
cs

+ Recent posts