Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

6. 그래픽 - DC의 정보 수정 본문

Windows/윈도우즈 API

6. 그래픽 - DC의 정보 수정

scarecrow1992 2021. 5. 4. 00:59

1. GDI 오브젝트

GDI(Graphic Device Interface)

3장에서 간략히 설명한 적 있다.

  • 윈도우즈 프로그램을 구성하는 세가지 DLL 중 하나
    • KERNEL, USER, GDI
  • 화면, 프린터 등의 출력장치를 통제하는 윈도우즈의 핵심 모듈
  • 윈도우즈 프로그램에서 모든 출력은 GDI를 통해서 화면과 프린터로 나가게 되어 있음

 

 

GDI Object

  • GDI가 그래픽 출력 및 출력조정에 사용되는 도구
    • ex : 펜(선 그리기), 브러시(면 채우기), 비트맵, 폰트(문자열 출력)...
    • 사용자는 그래픽을 그리기전에 DC에 원하는 오브젝트를 선택해줌으로써 원하는 모양과 속성으로 그래픽을 출력할 수 있다.
  • GDI 오브젝트는 모두 핸들로 관리되므로 사용자는 GDI 오브젝트 생성 함수를 부르고, 이 함수가 리턴하는 핸들을 받아서 사용하고, 삭제할때도 이 핸들만 이용하면 됨

 

DC가 BeginPaint나 GetDC 함수에 의해 처음 만들어졌을 때 디폴트로 선택된 GDI 오브젝트는 다음과 같다.

GDI 오브젝트 핸들 타입 설명 디폴트
HPEN 선을 그을 때 사용된다. 검정색의 가는 실선
브러시 HBRUSH 면을 채울 때 사용된다. 흰색
폰트 HFONT 문자 출력에 사용되는 글꼴 시스템 글꼴
비트맵 HBITMAP 비트맵 이미지 선택되지 않음
팔레트 HPALETTE 팔레트 선택되지 않음
비전 HRGN 화면상의 영역 선택되지 않음

이 장을 통해 GDI 오브젝트를 만들고 선택하며 출력을 바꾸는 방법에 대해 배워보겠다.

 

 


2. 스톡 오브젝트(Stock Object)

스톡 오브젝트(Stock Object)

  • 윈도우즈가 기본적으로 제공하는 GDI 오브젝트
  • 빈번하게 사용되므로 OS가 부팅될때 부터 미리 만들어짐
    • 즉, 사용자가 만들지 않아도 언제든지 사용 가능하며, 쓰고난 후에도 파괴할 필요 없음

아래 함수로 핸들을 얻어 사용하면 된다.

docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getstockobject

HGDIOBJ GetStockObject( int fnObject );
  • OS가 기본으로 제공하는 stock pen, brush, font 혹은 palletet에 대한 handle을 회수하는 함수
  • int fnObject :  사용하고자 하는 스톡 오브젝트를 지정

각 브러쉬별로 사용 가능한 OS가 다르므로 조심히 써야한다.

 

GDI object를 사용하는 예제 코드

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("GDI Object");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
 
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, NULL00)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
 
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR str[256];
    switch (iMessage) {    
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        Rectangle(hdc, 5050300200);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
 
cs

 

사각형에 채워지는 면의 색깔을 조절해보자

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
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
   HBRUSH MyBrush, OldBrush;
    // MyBrush : 그리기에 사용할 브러시 핸들
    // OldBrush : 원래 브러시를 잠시 저장할 핸들
    TCHAR str[256];
    switch (iMessage) {    
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
 
        // 회색의 브러시 핸들을 얻되 MyBrush 변수에 대입하기 위해 (HBRUSH)형으로 캐스팅 함
       MyBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
 
        // MyBrush를 사용하기 위해 hdc(DC)에 MyBrush(GDI Object)를 선택한다.
        // SelectObject는 새로 선택되는 값 이전에 쓰던 GDI Object를 리턴한다.
       OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
 
        // 회색 스톡 브러시를 선택한 후 사각형을 그렸으므로, 사각형의 내부는 회색으로 채워진다.
       Rectangle(hdc, 5050300200);
 
        // SelectObject를 한번 더 호출하여 원래의 GDI 오브젝트인 OldBrush로 복구한다.
        // 복구해야하는 상세한 이유에 대해서는 잠시후에 논의한다.
       SelectObject(hdc, OldBrush);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

코드의 작동 과정은 주석으로 설명하였다.

SelectObject 함수가 처음 등장했는데 아래와 같다.

HGDIOBJ SelectObject( HDC hdc, HGDIOBJ h );

특정 DC에 GDI Object를 선택하게끔 명령내리는 함수이다.

반환값 : 해당 DC가 이전에 선택하고 있던 GDI Object

 

 

 


3. 색상

  • 윈도우즈에서 색상을 표현하는 방법에 대해 학습
    • 도스 환경 : WHITE, YELLOW, RED등의 매크로 상수를 통해 16가지 색상만 사용 가능
    • 윈도우즈 환경 : 최대 천육백만가지의 색상 표현 가능

 

COLORREF

  • 색상값을 표현하기 위한 data type
  • 부호없는 32bit 크기의 정수형
  • 8비트씩 파란색, 초록색 ,빨간색의 농도를 나타내며 상위 8비트는 사용안됨
  • 각 색상 요소는 1byte의 크기를 가지므로 0~255 까지의 농도 표현 가능
  • ex) 0xff : 빨간색, 0xff0000 : 파란색
typedef DWORD COLORREF;

  • 일일이 각 비트마다 값을 넣는것은 기계적이며, 통상 쓰는 RGB 순서와 맞지 않기에 햇갈림
  • 그러므로 RGB 매크로 함수를 사용
1
#define RGB(r, g, b) ((COLORREF)(((BTYE)(r) | ((WORD)((BYTE)(g))<<8)) | (((DWORD)(BYTE)(b))<<16)))
cs

 

COLORREF 형 변수에서 각 색상 요소의 농도는 아래 방법으로 분리

1
2
3
#define GetRValue(rgb)        ((BYTE)(rgb))
#define GetGValue(rgb)        ((BYTE)(((WORD)(rgb)) >> 8))
#define GetBValue(rgb)        ((BYTE)((rgb) >> 16))
cs

 

 


4. 펜

  • 선을 그을 때 사용되는 GDI 오브젝트
  • 펜에 따라 그려지는 선의 모양이 결정됨
  • 윈도우즈에서 제공하는 스톡펜 : 힌색, 검정색, 투명펜 3가지
    • 이외의 파란색, 노란색등의 원색펜은 없음, 직접 만들어 써야한다.

펜을 만드는 함수

1
2
3
4
5
HPEN CreatePen(
  int      iStyle,
  int      cWidth,
  COLORREF color
);
cs
매개변수 효과
int iStyle 그려질 선의 모양을 지정한다.
굵기가 1일때만 효과 있는 변수, 2이상이면 무조건 실선으로 그려진다.

int cWidth 선의 폭(굵기)를 지정
디폴트 : 1
0 : 맵핑 모드에 상관없이 무조건 1픽셀 두께의 선이 만들어 짐
COLORREF color 선의 색상을 지정

 

return value

새로만든 펜의 handle

 

  • 모양, 굵기, 색상 세 가지 속서을 조합하면 다양한 형태의 펜을 만들 수 있음

 

예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
   HPEN MyPen, OldPen;
    TCHAR str[256];
    switch (iMessage) {    
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
       MyPen = CreatePen(PS_SOLID, 5, RGB(00255));
       OldPen = (HPEN)SelectObject(hdc, MyPen);
        Rectangle(hdc, 5050300200);
       SelectObject(hdc, OldPen);
       DeleteObject(MyPen);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

CreatePen 함수를 호출하여 굵기 5의 파란색 실선펜을 만든 후 이 펜의 핸들을 MyPen에 대입한다.

그리고 SelectObject로 이 펜을 DC에 선택한 후 사각형을 그렸으므로 굵고 파란색 테두리의 사각형이 그려지게 된다.

 

 

DeleteObject

  • GDI 오브젝트의 삭제에 사용되는 함수
1
BOOL DeleteObject( HGDIOBJ hObject );
cs
  • 현재 선택되어 있는 GDI 오브젝트는 삭제할 수 없음
    • 그래서 따로 저장된 OldPen을 DC가 다시 가지게끔 하여 선택을 해제시킴
1
2
SelectObject(hdc, OldPen);
DeleteObject(MyPen);
cs

위 코드에서 SelectObject에 OldPen을 넣으면, 뭐자피 현재 선택중인 MyPen이 반환되므로 아래처럼 한줄로 줄일 수 있다.

1
DeleteObject(SelectObject(hdc, OldPen));
cs

 

 

GDI 오브젝트를 만들고 사용하는 일반적인 절차

 

펜, 브러시, 폰트 등 모든 GDI 오브젝트는 위와 같은 절차를 거처 사용 및 관리된다.

속도를 위해 여러 방법을 쓸 수 있으니, 위 그림은 원론적인 내용만 이해하자.

 

 


5. 브러시

  • 채워지는 면을 채색하는 용도
  • 원이나 다각형의 내부를 채색할 때 현재 DC에 선택된 브러시가 사용됨
  • 스톡 브러시 : 회색, 흰색, 검정색 등의 단색브러시가 존재, 이외의 색들은 만들어 써야한다.
  • 만드는 함수만 다를 뿐 사용법은 이전에 살펴 본 펜과 동일

브러시를 만드는 함수

1
2
HBRUSH CreateSolidBrush( COLORREF color );
HBRUSH CreateHatchBrush( int iHatch, COLORREF color );
cs

SolidBrush : 단색 브러시

HatchBrush : 색상 + 무늬

설명
HS_BDIAGONAL 좌하향 줄무늬
HS_CROSS 바둑판 모양
HS_DIACROSS 좌하향 및 우하향 줄무늬
HS_FDIAGONAL 우하향 줄무늬
HS_HORIZONTAL 수평선
HS_VERTICAL 수직선

 

예제 코드

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
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
   HBRUSH MyBrush, OldBrush;
    HPEN MyPen, OldPen;
    TCHAR str[256];
    switch (iMessage) {    
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
       MyBrush = CreateHatchBrush(HS_BDIAGONAL, RGB(2550255));
       OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
        MyPen = CreatePen(PS_SOLID, 5, RGB(00255));
        OldPen = (HPEN)SelectObject(hdc, MyPen);
 
        Rectangle(hdc, 5050300200);
        
       SelectObject(hdc, OldBrush);
        SelectObject(hdc, OldPen);
       DeleteObject(MyBrush);
        DeleteObject(MyPen);
        EndPaint(hWnd, &ps);        
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

 


7. 투명 오브젝트

스톡 오브젝트의 도표를 보면 브러시와 펜은 투명색의 NULL_BRUSH(-HOLLOW_BRUSH)와 NULL_PEN 이라는 것이 있는데 이 오브젝트는 그리기를 하지 않는 오브젝트라는 뜻이다.

다음 예제코드를 통해 투명 오브젝트가 무엇인지 경험해보자.

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
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
    HBRUSH MyBrush, OldBrush;
    HPEN MyPen, OldPen;
    TCHAR str[256];
    switch (iMessage) {    
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        for (int i = 0; i < 250; i+= 5) {
            MoveToEx(hdc, 0, i, NULL);
            LineTo(hdc, 600, i);
        }
 
        // 빨간 펜, 초록 브러시
        MyBrush = CreateSolidBrush(RGB(02550));     // 빨간 펜
        OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
        MyPen = CreatePen(PS_SOLID, 5, RGB(25500)); // 초록 브러시
        OldPen = (HPEN)SelectObject(hdc, MyPen);
        Ellipse(hdc, 2020150150);
 
        // 빨간 펜, 널 브러시
        SelectObject(hdc, GetStockObject(NULL_BRUSH));
        Ellipse(hdc, 22020350150);
 
        // 널 펜, 초록 브러시
        SelectObject(hdc, MyBrush);
        SelectObject(hdc, GetStockObject(NULL_PEN));
        Ellipse(hdc, 42020550150);
 
        DeleteObject(SelectObject(hdc, OldBrush));
        DeleteObject(SelectObject(hdc, OldPen));
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

투명 브러시의 경우 안쪽에 아무것도 안그린것을 확인할 수 있다.

GDI 그리기 함수들은 항상 선택된 오브젝트를 무조건 사용하도록 되어있다. 즉, 테두리만 따로 그리거나 안만 채우는 함수는 제공되지 않으며, 둘 중 하나만 그리고 싶을때는 그리고 싶지 않은 부분에 대해 투명 오브젝트를 선택해 놓고 그려야 한다.

 

 

 

요약

  • GDI 오브젝트
    • GDI : 윈도우즈 프로그램을 구성하는 세가지 DSS 중 하나
      • KERNEL, USER, GDI
    • 윈도우즈 프로그램에서 모든 출력은 GDI를 통해야만 이루어짐
    • 그래픽을 그리기 전 DC에 원하는 GDI 오브젝트를 선택시켜 원하는 출력을 발생시킨다.
    • 핸들을 통해 접근한다.
    • 생성
      • 오브젝트 종류에 따라 별개의 함수로 생성함
      • CreatePen, CreateSoldBrush, CreateHatchBrush...
      • 생성시 색깔, 무늬, 선 굵기 등 다양한 특성 선택 가능
    • 선택
      • SelectOject : 특정 DC에 GDI Object를 선택하게끔 한다.
    • 삭제 : DeleteObject 함수의 인수로 핸들 전달
  • 스톡 오브젝트
    • 윈도우가 기본적으로 제공하는 GDI 오브젝트
    • OS 부팅시 미리 만들어짐
    • GetStockObject 함수로 스톡오브젝트의 핸들을 얻을 수 있다.

 

 

 

 

 

'Windows > 윈도우즈 API' 카테고리의 다른 글

6. 그래픽 - 비트맵  (0) 2021.05.05
6. 그래픽 - 그리기 모드  (0) 2021.05.05
5. 리소스 - 문자열 테이블(string table)  (0) 2021.05.01
5. 리소스 - 액셀러레이터(Accelerator)  (0) 2021.05.01
5. 리소스 - 메뉴  (0) 2021.05.01
Comments