API Device Context

IT/개발공부 / / 2020. 9. 7. 18:55
728x90
반응형

DC

 

Device Context란

 

DC란 출력에 필요한 모든 정보를 가지는 구조체이며 GDI 모듈에 의해 관리됩니다. 문자열의 모양을 지정하는 폰트, 선의 색상과 굵기, 채움 무늬와 색상, 그리기 모드 등등이 모두 출력에 필요한 정보들입니다.

 

윈도우를 만들고 그림을 그리려면 반드시 DC의 핸들을 얻어야 합니다. DC는 임의의 장치에 출력을 할 때 사용하는 다양한 속성의 지닌 일종의 구조체 입니다. DC는 하나의 장치에 연결되어 있습니다. 사용자는 DC에 출력을 하면 DC가 지닌 여러 속성을 사용해서 DC가 연결된 장치에 출력됩니다.

 

DC를 얻는 방법은 다양하며, 제거 방법도 다양도 각기 다릅니다.

 

DC 얻기 DC 해제 Description
GetDC() ReleaseDC() Client 영역을 위한 DC를 얻는다.
GetDCEx() ReleaseDC() GetDC()의 확장 함수
GetWindowDC() ReleaseDC() 윈도우 전체를 위한 DC를 얻는다.
BeginPaint() EndPaint() 무효화 영역을 위한 DC를 얻는다.
CreateCompatibleDC() DeleteDC() 메모리 DC, 주로 비트맵을 사용하기 위해 얻는다.
CreateDC() DeleteDC() 바탕화면, 프린터를 위한 DC를 얻는다.
CreateMetaFile() CloseMetaFile() 메타파일을 위한 DC를 얻는다.
CreateIC() DeleteIC() 정보 DC를 얻는다.

 

클라이언트 DC 얻기

HDC GetDC(HWND hWnd);
ReleaseDC(HWND hwnd, HDC hdc);

 

바탕화면 DC 얻기

HDC hdc = GetDC(0);
HDC hdc = CreateDC(“DISPLAY”, 0, 0, 0);

 

윈도우가 다른 윈도우 뒤에 있다가 앞으로 나올 때 다시 그려야 하는 영역을 무효화 영역이라고 합니다.

무효화 영역

무효화 영역이 발생하는 경우

  • 윈도우를 옮기거나 제거 했을 때 이전에 감추어졌던 윈도우 영역이 보이게 될 때
  • 윈도우의 크기를 조정했을 때
  • ScrollWindow(), ScrollDC() 함수를 사용한 경우
  • InvalidateRect(), InvalidateRgn() 함수를 사용하는 경우
  • 윈도우 일부에 겹친 DialogBox나 메시지 박스가 제거 될 때
  • 메뉴가 나타났다 사라질 때
  • 풍선도움말이 나타났을 때

다음 경우는 운영체제가 화면을 저장한 후 복구해 줍니다.

  • 마우스 커서가 클라이언트 영역을 지나갈 때
  • 아이콘이 클라이언트 영역을 지나갈 때

WM_PAINT

 

무효화 영역이 발생하면 운영체제는 WM_PAINT 메시지를 해당 윈도우 프로시져에 보냅니다.

 

하나의 윈도우는 내부적으로 Paint Information Struct를 가지고 있습니다. 이 구조체 안에 무효화 영역을 둘러싸는 가장 작은 사각형의 좌표를 지닙니다.

 

WM_PAINT는 2번 메시지 큐에 들어오지 않고 단지 이 좌표만이 Update 됩니다.

GetUpdateRect()를 사용하면 이 좌표를 얻을 수 있습니다.

 

BeginPaint/EndPaint

 

클라이언트 DC얻기

WM_PAINT 메시지 루틴에서 클라이언트 DC를 얻고 사용할 수 있는 방법입니다. WM_PAINT 메시지 처리 루틴에서는 DC핸들을 GetDC로 얻디 않고 BeginPaint 함수로 얻으며 해제할 때는 EndPaint 함수를 사용합니다.

 

GetDC는 DC 핸들을 얻는 일반적인 방법이며, BeginPaint는 WM_PAINT 메시지 내에서 사용하는 특수한 방법입니다.

HDC BeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint);
BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT *lpPaint);

 

BeginPaint 함수는 윈도우 핸들 외에도 페인트 정보 구조체를 인수로 요구하여 이 구조체에 그림 그리기에 필요한 여러 가지 복잡한 정보를 리턴합니다.

 

BeginPaint는 아래와 같은 일을 합니다.

  • DC를 만들고 UpdateRegion을 DC의 Cliping 영역으로 지정합니다.
  • 무효화 영역을 지우기 위해 WM_ERASEBKGND 메시지를 보냅니다.
  • PAINTSTRUCT 구조체를 채웁니다.
  • Caret 이 있을 경우 그리기 전에 Hide하고 EndPaint()에서 Show 합니다.
  • 무효화 영역을 유효화 합니다.
case WM_PAINT:
 return 0;

위의 코드는 절대로 사용하면 안됩니다. 무효화 영역이 유요화 되지 않으므로 WM_PAINT 가 무한반복 호출됩니다.

 

PAINTSTRUCT

PAINTSTRUCT 구조체는 발생된 무효화 영역에 대한 여러가지 정보를 얻어오기 위해 사용합니다.

typedef struct tagPAINTSTRUCT
{
     HDC hdc; // dc handle
     BOOL fErase; // 배경을 지운경우 FALSE, 지우지 않은 경우 TRUE
     RECT rcPaint; // 클리핑 영역을 포함하는 최소 사각형
     BOOL fRestore; //Reserved; used internally by the system
     BOOL fIncUpdate; //Reserved; used internally by the system 
     BYTE rgbReserved[32]; //Reserved; used internally by the system
} PAINTSTRUCT, *PPAINTSTRUCT;

대부분의 경우 fErase는 FALSE 입니다. 즉 운영체제가 배경을 지웁니다.

InvalidateRect(hwnd, 0, FALSE);

하지만 위의 경우에는 무효화 영역을 반들고 배경을 지우지 않게 합니다. 그러므로 fErase 값은 TRUE 입니다.

 

rcPaint는 현재 DC가 출력할 수 있는 클리핑 영역을 가르키는 데 이를 잘 이용할 경우 프로그램의 성능을 훨씬 뛰어나게 만들 수 있습니다.

화면에 원하는 그림을 출력하기 위해서는 반드시 WM_PAINT 메시지에서 출력해야 합니다. WM_PAINT 메시지 에서는 클라이언트 영역에 그리기 위한 모든 정보를 알고 있어야 합니다.

 

#include <windows.h>
#include <tchar.h>

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
       switch( msg )
       {
          case WM_LBUTTONDOWN:
          {          
              HDC hdc = GetDC(hwnd);
              Rectangle(hdc, 10,10,100,100);
              ReleaseDC(hwnd, hdc);
          }
          return 0;
          
          case WM_DESTROY:
              PostQuitMessage(0);
              return 0;
       }
       return DefWindowProc(hwnd, msg, wParam, lParam);
}

위 예제는 마우스 왼쪽 버튼 클릭시 클라이언트 DC를 얻어 사각형을 출력하는 예제입니다.

 

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
      switch( msg )
      {
          case WM_LBUTTONDOWN:
          {
             HDC hdc = GetDC(hwnd);
             Rectangle(hdc, 120, 10, 210, 100);
             ReleaseDC(hwnd, hdc);
          }
          return 0;

          case WM_RBUTTONDOWN:
          {
             RECT r = {120, 10, 210,100};
             InvalidateRect(hwnd, &r, TRUE);
          }
          return 0;
          
          case WM_PAINT:
          {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            Rectangle(hdc, 10,10,100,100);
            EndPaint(hwnd, &ps);
          }
          return 0;
          
          case WM_DESTROY:
          PostQuitMessage(0);
          return 0;
      }
      return DefWindowProc(hwnd, msg, wParam, lParam);
}

위의 예제는 무효화 영역에 관련된 예제이다. 프로그램을 실행하면 화면을 그리기 위해 WM_PAINT 메시지가 호출되며 좌측 상단에 사각형이 그려지게 됩니다.

 

만약 마우스 오른쪽 버튼을 클릭하면 강제로 무효화 영역을 발생시키게 되며, 발생된 무효화 영역에 출력되었던 사각형은 사라지게 됩니다.

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기