윈도우 어플리케이션 (5) : 그래픽
GDI : 화면, 프린터 등 출력장치를 제어하는 윈도우즈 핵심모듈. 윈도우즈의 모든출력은 GDI를 통해 나간다.
GDI Object : 그래픽 출력에 사용되는 도구. 펜, 브러시, 비트맵 폰트 등.
DC : GDI Object를 모아둔것. GDI는 현재 DC에 선택된 GDI Object를 사용한다.
GetDC나 BeginPaint로 DC를 처음 만들게되면 펜(선)타입은 디폴트로 검정색 가는실선, 브러시(면)는 흰색을 사용하게됨
StockObject : 윈도우즈가 기본으로 제공하는 GDI오브젝트. 부팅할때부터 미리 만들어둠
BLACK_BRUSH, WHITE_BRUSH, NULL_BRUSH, BALCK_PEN, DC_BRUSH, ANSI_FIXED_FONT 등
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
HBRUSH MyBrush, OldBrush;
switch(Message) {
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
MyBrush=(HBRUSH)GetStockObject(GRAY_BRUSH);
OldBrush=(HBRUSH)SelectObject(hdc,MyBrush);
Rectangle(hdc,50,50,300,200);
SelectObject(hdc,OldBrush);
EndPaint(hwnd,&ps);
break;
...
}
GetStockObject로 GRAY_BRUSH핸들을 가져와서 타입캐스팅 후 MyBrush에 넣고, SelctObject로 해당 DC에 기존 오브젝트 대신 새로운 오브젝트를 선택하게 된다. 그 후 Rectangle로 DC에 세팅된 GDI 오브젝트들로 그림을 그리게 된다.
브러시는 GRAY_BRUSH, 나머지는 디폴트이기 때문에 검정색 가는실선, 회색바탕 사각형이 그려지는 것이다.
SelectObject는 반환값이 이전 오브젝트 핸들이기 때문에 OldBrush에 저장하며, 그림을 그리고 난 뒤에는 SelectObject를 통해 다시 기존 브러시로 바꾼다.
색상
typedef DWORD COLORREF; 부호없는 32bit 정수형. 상위 8bit는 사용하지 않는다. B G R 순이다.
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
#define GetRValue(rgb) ((BYTE)(rgb))
#define GetGValue(rgb) ((BYTE)(((WORD)(rgb))>>8))
#define GetBValue(rgb) ((BYTE)((rgb)<<16))
펜 (선)
CreatePen(fnPenStyle, nWidth, crColor)
- fnPenStyle : 선 모양을 지정. PS_SOLID, PS_DASH, PS_DOT 등이 있다. 선 모양은 굵기가 1px일때만 효과가 있다.
- nWidth : 선 굵기. 0인경우엔 매핑모드에 상관없이 무조건 1픽셀이 된다.
- crColor : 선의 색상을 지정한다. RGB(0,0,255) 등
리턴값은 위의 세팅으로 만들어진 펜의 핸들이 된다.
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
HPEN MyPen, OldPen;
switch(Message) {
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);
EndPaint(hwnd,&ps);
break;
...
}
StockObject에 기본으로 존재하는 펜이 아닌 새로만든 펜은 메모리에 올라가기 때문에 DeleteObject로 삭제해줘야한다.
현재 사용중인 오브젝트는 삭제할 수 없기 때문에 기존 펜인 OldPen으로 변경 후 삭제한다.
브러쉬 (면)
CreateSolidBrush(crColor);
CreateHatchBrush(fnStyle, crColor);
- fnStyle : 브로시 모양. HS_BDIAGONAL, HS_CROSS, HS_DIAGCROSS, HS_VERTICAL, HS_HORIZONTAL 등이 있음
두 함수 모두 리턴값이 브러시 핸들이며 펜과 동일하게 사용 후 삭제해주면 된다.
그리기모드
그리기 중 다른 그림과 겹치는부분에 대해 어떻게 처리할건지 설정할 수 있다.
GetROP2(hdc);
SetROP2(hdc, fnDrawMode);
- fnDrawMode : R2_BLACK, R2_WHITE, R2_NOP, R2_NOT, R2_COPYPEN 등. 비트 and, or, xor 등도 있음
xor을 사용하면 2번 겹치게 그릴때 다시 원복이 된다는 특징이 있다.
비트맵
HBITMAP MyBitmap, OldBitmap;
BITMAP bit;
int bx, by;
MyBitmap=LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
hdc=BeginPaint
MemDC=CreateCompatibleDC(hdc);
OldBitmap=(HBITMAP)SelectObject(MemDC,MyBitmap);
GetObject(MyBitmap, sizeof(BITMAP), &bit);
bx=bit.bmWidth;
by=bit.bmHeigth;
BitBlt(hdc, 0, 0, bx, by, MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC, OldBitmap);
DeleteObject(MyBitmap);
DeleteDC(MemDC);
EndPaint(hwnd, &ps)
메모리 DC
비트맵은 크기가 큰 데이터 덩어리라 출력이 오래걸리기 때문에 메모리 DC에 미리 그려두고 화면 DC로 출력한다.
CreateCompatibleDC 함수는 화면 DC 핸들을 인자로 받으며 메모리에 인자로 받은 DC와 동일한 환경의 DC를 생성한다.
LoadBitmap : 리소스에 있는 비트맵 핸들을 가져온다.
SelectObject : 이 함수로 비트맵을 메모리 DC에서 선택한다. 비트맵은 메모리 DC에서만 선택할 수 있다.
GetObject를 통해 저장할 비트맵의 정보를 가져와서 BITMAP 구조체에 넣은뒤 x길이와 y길이를 얻어온다.
BitBlt : DC 사이에 영역을 고속복사한다. 메모리DC의 0, 0 위치를 대상의 0, 0에 123(bx), 160(by) 크기만큼에 복사한다.
- SRCCOPY(영역을 복사), MERGECOPY(영역끼리 AND연산), MERGEPAINT(OR), BLACKNESS(영역을 검정색으로채움) 등
비트맵을 지우기 전에 선택 해제를 위해서 OldBitmap 변수가 필요하다.
BitBlt 말고도 StretchBlt 라는 함수도 있는데, 이 함수는 비트맵을 복사할때 확대및 축소가 가능하다.
StretchBlt(hdc, 0, 0, 246, 320, MemDC, 0, 0, 123, 160, SRCCOPY);
WM_CREATE에서 LoadBitmap으로 미리 로드하고 출력은 WM_PAINT에서 한뒤 비트맵을 삭제하는 DeleteObject는 WM_DESTROY에서 실행하는게 정석이다.
DrawBitmap(hdc, ox, oy, MyBitmap); 함수로 LoadBitmap, DeleteObject를 제외한 나머지기능을 바로 사용할 수 있다.
폰트
CreateFont 함수로 폰트 오프젝트를 생성한다음 SelectObject로 DC의 폰트를 변경, TextOut으로 문자열을 출력하면 생성했던 폰트로 글자가 출력된다. 하지만 CreateFont의 매개변수가 복잡하기 때문에 사용할때 찾아봐야한다.
또한 LOGFONT 구조체로 폰트를 미리 세팅하고 CreateFontIndirect 함수로 세팅한 폰트를 DC에 생성하게 할수있다.
SetTextConor(hdc, crColor); SetBkColor(hdc, crColor);, setBkMode(hdc, iBkMode);
이 함수들로 글씨색, 배경을 세팅할 수 있으며 iBkMode에는 OPAQUE(불투명한배경), TRANSPARENT(투명한배경)을 전달하여 배경의 속성을 지정할 수 있다.
CreateFont의 세번째 인수는 0~900까지 10당 1도씩 0도~90도까지 글자를 회전시켜 출력할 수 있다.