일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스토어드 프로시저
- DP
- two pointer
- Stored Procedure
- Brute Force
- 다익스트라
- Trie
- MYSQL
- Dijkstra
- 이진탐색
- SQL
- String
- 그래프
- union find
- binary search
- Hash
- Two Points
- Today
- Total
codingfarm
6. 그래픽 - DC의 정보 수정 본문
1. GDI 오브젝트
GDI(Graphic Device Interface)
- 윈도우즈 프로그램을 구성하는 세가지 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, NULL, 0, 0)) {
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, 50, 50, 300, 200);
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, 50, 50, 300, 200);
// 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(0, 0, 255));
OldPen = (HPEN)SelectObject(hdc, MyPen);
Rectangle(hdc, 50, 50, 300, 200);
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에 선택한 후 사각형을 그렸으므로 굵고 파란색 테두리의 사각형이 그려지게 된다.
- 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(255, 0, 255));
OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
MyPen = CreatePen(PS_SOLID, 5, RGB(0, 0, 255));
OldPen = (HPEN)SelectObject(hdc, MyPen);
Rectangle(hdc, 50, 50, 300, 200);
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(0, 255, 0)); // 빨간 펜
OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
MyPen = CreatePen(PS_SOLID, 5, RGB(255, 0, 0)); // 초록 브러시
OldPen = (HPEN)SelectObject(hdc, MyPen);
Ellipse(hdc, 20, 20, 150, 150);
// 빨간 펜, 널 브러시
SelectObject(hdc, GetStockObject(NULL_BRUSH));
Ellipse(hdc, 220, 20, 350, 150);
// 널 펜, 초록 브러시
SelectObject(hdc, MyBrush);
SelectObject(hdc, GetStockObject(NULL_PEN));
Ellipse(hdc, 420, 20, 550, 150);
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 : 윈도우즈 프로그램을 구성하는 세가지 DSS 중 하나
- 스톡 오브젝트
- 윈도우가 기본적으로 제공하는 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 |