1 / 63

Chapter 5 Windows GDI 작업 : 텍스트 및 그래픽 출력

Chapter 5 Windows GDI 작업 : 텍스트 및 그래픽 출력. 이 장에서는. - WM_PAINT 메시지 사용하기 - GDI 그리기 표면 (drawing surface) 검사하기 - 텍스트 그리기 - 펜 , 브러시 , 비트맵 사용하기 - 다양한 모양 그리기. 윈도우즈 GDI(Graphic Device Interface). 그래픽의 출력을 담당 화면에 그리는 그래픽만 지원하는 것이 아니라 프린터에 프린트하는 기능도 담당. 클라이언트 영역. 유효화 (Validating)

liza
Download Presentation

Chapter 5 Windows GDI 작업 : 텍스트 및 그래픽 출력

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 5Windows GDI 작업: 텍스트 및 그래픽 출력

  2. 이 장에서는... • - WM_PAINT 메시지 사용하기 • - GDI 그리기 표면(drawing surface) 검사하기 • - 텍스트 그리기 • - 펜, 브러시, 비트맵 사용하기 • - 다양한 모양 그리기

  3. 윈도우즈 GDI(Graphic Device Interface) • 그래픽의 출력을 담당 • 화면에 그리는 그래픽만 지원하는 것이 아니라 프린터에 프린트하는 기능도 담당

  4. 클라이언트 영역 • 유효화(Validating) • 사용자 혹은, 자동 윈도우 프로세스와 같은 무엇인가가 윈도우의 클라이언트 영역을 훼손하면, 윈도우즈는 WM_PAINT 메시지를 응용 프로그램으로 보낸다. • 프로그램은 윈도우즈에게 그 메시지를 받아서 처리했다는 것을 알려야 한다. 이렇게 윈도우즈에게 알리는 과정을 일컬어서 사각형(그려질 영역)을 유효화한다고 말한다. • 그려야 할 사각형 정의 • 그릴 필요가 없는 영역은 그리지 않도록 한다. • 따라서 그릴 필요가 있는 영역인 무효 사각형(invalid rectangle)만 신경을 쓰면 되며, • 이것은 WM_PAINT 메시지에 따라오는 자료 구조에 포함되어 있다.

  5. WM_PAINT 메시지를 처리하는 두 가지 방법 • BeginPaint() .. EndPaint(). • 장점: 이 함수 쌍은 어떤 부가적인 코드의 추가 없이 자동으로 유효화(validating)을 수행한다. • 단점: 무효 사각형을 나타내는 rcPaint 속성은 또한 현재 윈도우의 클리핑 영역이기도 하다. 클리핑 영역 외부에는 어떤 것도 그릴 수 없다. 이는 즉, 무효 영역이 아닌 클라이언트 영역에 무언가를 그리고 싶다면 나머지 클라이언트 영역에 접근하기 위해 rcPaint를 다시 정의해야 한다는 것을 뜻한다. • GetDC() .. ReleaseDC() • 장점: 반환된 그리기 표면은 전체 클라이언트 영역을 클리핑 사각형으로 삼는다. 따라서 클라이언트 영역을 그리기 위해 매번 무효 사각형을 다시 정의할 필요가 없다. • 단점: 무효 사각형을 유효화하기 위해 직접 ValidateRect()를 호출해야 한다. 그렇지 않으면 윈도우즈는 언제까지나 응용 프로그램에 WM_PAINT 메시지를 보낼 것이다. 그러나 WM_PAINT 메시지를 받지 않고 윈도우를 그리고자 할 때에는 GetDC()를 사용하는 것이 최선이다

  6. BeginPaint() PAINTSTRUCT ps; // a Windows paint structure HDC hdc; // handle to graphics device context case WM_PAINT: { // obtain handle to device context hdc = BeginPaint(hwnd, &ps); // paint client area // release handle and validate window EndPaint(hwnd, &ps); // always tell Windows that you processed the message return(0); } break;

  7. PAINTSTRUCT typedef struct tagPAINTSTRUCT { HDC hdc; // handle to device context BOOL fErase; // flags whether app should redraw background RECT rcPaint; // clipping rectangle BOOL fRestore; // reserved BOOL fIncUpdate; // reserved BYTE rgbReserved[32]; // reserved } PAINTSTRUCT;

  8. rcPaint • 직사각형의 네 점을 가지는 RECT 구조체 자료형 • 직사각형이 무효(invalid) 사각형을 나타낸다 • 무효 사각형은 다시 그릴 필요가 있는 유일한 영역 typedef struct _RECT { LONG left; // leftmost edge of the RECT LONG top; // topmost edge of the RECT LONG right; // rightmost edge of the RECT LONG bottom; // bottom-most edge of the RECT } RECT;

  9. 무효 사각형

  10. 그냥 전체 client 영역을 그리면 안될까? • rcPaint는 단지 무효 사각형일 뿐만 아니라, 윈도우의 클리핑 사각형이기도 하다. • 따라서 클리핑 사각형을 벗어나는 것은 그린다 해도 그려지지 않을 것이다. • 특히 전체 클라이언트 영역을 그리고 싶다면, 문제가 있다.

  11. GetDC() 는 도대체? • 클리핑 사각형은 전체 클라이언트 영역 • 더 골치가 아픈데도 불구하고 GetDC() .. Release()보다 WM_PAINT 메시지 내에 BeginPaint() .. EndPaint()를 사용하는 이유는 무엇인가? • 그 이유는 GetDC() .. ReleaseDC()는 무효 사각형을 유효화시키지 않기 때문이다. • BeginPaint() .. EndPaint() 쌍은 이 유효화를 자동으로 수행

  12. InvalidateRect() BOOL InvalidateRect( HWND hWnd, // handle of window to invalidate CONST RECT *lpRect, // ptr to rect area to invalidate BOOL bErase); // erase flag for BeginPaint() • 강제로 lpRect 부분을 invalidate 시킴 • 원하는 부분을 그리고 싶을 때 사용 • 만약 언제나 전체 클라이언트 영역을 처리하고 싶다면, lpRect에 NULL를 넣으면 된다.

  13. BeginPaint()..EndPaint()를 사용전체 윈도우 클라이언트 영역을 무효화 case WM_PAINT: { // invalidate the whole window InvalidateRect(hwnd,NULL,TRUE); // start painting hdc = BeginPaint(hwnd,&ps); // do graphics here // stop painting EndPaint(hwnd, &ps); return(0); } break;

  14. 만약 어떤 그래픽 작업도 직접 하고 싶지 않다면 case WM_PAINT: { // validate whole window; basically ignore message ValidateRect(hwnd,NULL); return(0); } break;

  15. GetDC() • GetDC()를 이용하면 클리핑 사각형은 전체 클라이언트 영역이 되기 때문 • 무효 사각형을 유효화하지 않는다: ValidateRect()함수를 사용. BOOL ValidateRect( HWND hWnd, // handle of window CONST RECT *lpRect); // pointer to // RECT area to validate

  16. WM_PAINT 메시지 처리에서 GetDC()..ReleaseDC()를 사용 case WM_PAINT: { // get the device context from Windows hdc = GetDC(hwnd); // do graphics here // release the device context to Windows ReleaseDC(hwnd,hdc); // validate the window ValidateRect(hwnd, NULL); return(0); } break;

  17. 출력-표면(Display-Surface)의 기초 • 해상도(Resolution): 이 수치는 디스플레이 상의 픽셀의 숫자를 의미한다. 일반적인 해상도는 640x480, 800x600 그리고 1,024x768이다. • 색깊이(Color Depth): 이 수치는 한 색상에 사용할 수 있는 비트 수를 의미하며, 비디오 카드의 메모리 크기에 좌우된다. 일반적인 비디오 카드는 8, 16, 24 개의 픽셀당 비트 수(bits per pixel; bpp)를 가지며, 이는 픽셀의 색상을 결정하기 위해 1, 2, 또는 3 바이트가 필요하다는 뜻이다. 표 5-1은 여러 비트 깊이에 따른 색상수가 나와있다. • 색공간(Color Space): 이 수치는 색깊이에 따른 실제 사용 가능한 색상의 수를 말한다. 예를 들어, 8비트는 256 색이 가능하고, 16비트는 65,536 색이 가능하다.

  18. 각 비트 깊이에 따른 색상의 수

  19. 비디오 카드와 color depth • 대부분의 비디오 카드 • 15비트나 16비트 컬러 모드에 픽셀당 2바이트를 사용 • 24비트나 32비트 컬러 모드의 경우에는 픽셀당 4바이트 • 따라서 모든 픽셀은 WORD (32bit=4bytes)나 QUAD (32bit=4bytes) 바이트로 정렬되어있다. 이러한 정렬로 인해 디스플레이 메모리 접근과 래스터화(rasterization)의 속도가 향상될 수 있다.

  20. bpp • 픽셀당 비트(bits per pixel) or • 픽셀당 바이트(bytes per pixel) • 문맥에 따라서 적절히 파악해야 한다. • 예를 들어, 24 bpp는 당연히 픽셀당 비트 • 3 bpp는 픽셀당 바이트

  21. 비디오 모드와 색깊이와 메모리 요구사항 • 2MB 비디오 카드는 대부분의 해상도와 색깊이를 지원할 수 있지만 • 1MB 카드는 가까스로 하이컬러(16bpp) 모드에서 800x600을 처리할 수 있다.

  22. RGB 모드 • 디스플레이 카드가 8bpp를 넘는 비디오 모드 • 순수한 RGB(Red, Green, Blue) 모드

  23. 팔레트 모드 • 색상 간접지정(color indirection)이라는 형식을 사용 • 8 비트(1 바이트)로 각 픽셀을 나타낸다. • 픽셀당 총 256개의 서로 다른 색상이나 수치를 가질 수 있다. • 색상조사표(Color Look-Up Table)즉, CLUT • 256개의 항목 각각은 모두 빨강, 초록, 파랑을 위해 8비트씩을 가지고 있다 • 따라서, 모든 픽셀은 24비트를 가진다. • 윈도우즈가 약 20개 정도를 가져가서 윈도우들이나 컨트롤들을 고유한 방법으로 그린다. 그러니까 응용 프로그램이 정의할 수 있는 색상은 겨우 236개만 남는 셈이다. • 각 응용 프로그램이 자신의 236개의 색을 정의할 수 있는 게 아니라, 모든 응용 프로그램이 같은 236개의 색상을 공유해야 한다.

  24. 윈도우즈 색상 관리 • 두 개의 주요한 자료 구조 • COLORREF • 빨강, 초록, 파랑 요소로 구성된 간단한 4 바이트 구조체. 색상을 그때그때 만들고자 할 때 사용할 수 있다. • PALETTEENTRY • 좀더 복잡한 4 바이트 구조체로 팔레트를 생성하는 데 사용된다. 표준 RGB 요소에 부가하여 Flags 요소가 들어있다.

  25. 윈도우즈 색상 관리 typedef struct tagCOLORREF { BYTE bRed; // red component BYTE bGreen; // green component BYTE bBlue; // blue component BYTE bDummy; // always 0 } COLORREF; typedef struct tagPALETTEENTRY { BYTE peRed; // red component BYTE peGreen; // green component BYTE peBlue; // blue component BYTE peFlags; // control flags set to PC_NOCOLLAPSE } PALETTEENTRY;

  26. RGB macro의 사용 // to create white COLORREF white = RGB(255,255,255); // to create pure red COLORREF red = RGB(255,0,0);

  27. 텍스트 출력 • DirectX는 폰트나 텍스트를 지원하지 않는다. • 단어를 출력하기 위해서는 직접 텍스트를 코딩 하거나, 자신의 텍스트 시스템을 만들거나 (보기 좋게 만들려면 다중 크기 폰트를 포함해야 함) GDI를 사용해야 한다.

  28. 고정피치(fixed pitch)와 가변피치(proportional pitch) 폰트

  29. 텍스트 출력 • TextOut() • 제일 간단한 방법으로 형식화(formatting)나 처리 능력은 없다. 이 함수는 간단히 정적인 문자열을 출력한다. • DrawText() • 제일 복잡한 방법이며, 조정, 클리핑 등의 더 많은 제어가 가능하다. 이 책에서는 이 함수를 사용하지 않는다. 그러나, 이 절의 말미에 프로토타입을 볼 수 있을 것이다.

  30. TextOut() BOOL TextOut( HDC hdc, // handle of device context int nXStart, // x-coordinate of starting position int nYStart, // y-coordinate of starting position LPCTSTR lpString, // address of string to print int cbString); // number of characters in string

  31. TextOut() 예제 • 카운터의 수치를 윈도우 클라이언트 영역의 (0,0)에 출력 char buffer[80]; // used to build up strings static int counter = 0; // used to count case WM_PAINT: { // start painting hdc = BeginPaint(hwnd,&ps); // create the output string and get its length int length = sprintf(buffer,”The Count is %d “,(int)counter++); // print the text TextOut(hdc,0,0,buffer,length); // end painting EndPaint(hwnd,&ps); return(0); } break;

  32. 매 사이클마다 출력되기를 원한다면 • 앞의 예제의 한가지 문제점은 WM_PAINT 메시지가 보내질 때만 텍스트가 출력된다는 것이다. • 매 사이클마다 출력되기를 원한다면, // enter main event loop while(1) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // test whether the message is WM_QUIT if (msg.message == WM_QUIT) break; // translate any accelerator keys TranslateMessage(&msg); // send the message to the window proc DispatchMessage(&msg); } // end if // main game processing goes here // get the graphics device context hdc = GetDC(hwnd); // create the output string and get its length int length = sprintf(buffer,”The Count is %d “,(int)counter++); // print the text TextOut(hdc,0,0,buffer,length); // release the device context ReleaseDC(hwnd,hdc); } // end while

  33. DrawText() • 더 많은 제어를 (조정, 클리핑 등) 가능케 한다. int DrawText( HDC hDC, // handle to device context LPCTSTR lpString, // pointer to string to draw int nCount, // string length LPRECT lpRect, // clipping rectangle UINT uFormat); // formatting flags

  34. 텍스트에 색깔 넣기 • 전경과 배경 • 각 텍스트 문자는 배경과 전경이 있다. 전경은 문자 자체고, 배경은 문자를 포함하는 구획이다. • 투명도 • 텍스트 배경을 투명하게 하면 텍스트는 날인(문자열을 출력할 때 더 선호되는 방식)되기보다는 그려진 것처럼 보인다. • 불투명도(투명도 없이) • 문자의 배경 색깔이 아래의 모든 것들을 가리게 한다.

  35. 세 단계 • 텍스트의 투명도를 정한다. • 텍스트의 전경 색상을 정한다. • 텍스트의 배경 색상을 정한다.

  36. SetBkMode() int SetBkMode( HDC hdc, // handle of device context int iBkMode); // flag specifying background mode • iBkMode는 배경 모드로 TRANSPARENT나 OPAQUE 중 하나

  37. SetTextColor() 와 SetBkColor() • SetTextColor() • 텍스트 자체의 색상을 정하는 데 사용 • SetBkColor() • 텍스트 아래의 배경색을 (그리고 다른 GDI 객체의 배경색도) 정하는 데 사용 COLORREF SetTextColor( HDC hdc, // handle of device context COLORREF crColor); // text color COLORREF SetBkColor( HDC hdc, // handle of device context COLORREF crColor); // background color

  38. 저장-변경-사용-복원 사이클 - 1 • 대부분의 GDI 함수는 지금 변경하고자 하는 것의 원래 값을 반환 • 빨간 텍스트와 파란 텍스트를 두 가지 배경 모드(투명과 불투명)에서 출력하는 예 COLORREF old_text_color, old_back_color; // save the old colors // get the device context hdc = GetDC(hwnd); // set transparency mode SetBkMode(hdc,TRANSPARENT); // set colors and save old old_text_color = SetTextColor(hdc,RGB(255,0,0)); old_back_color = SetBkColor(hdc,RGB(0,0,0));

  39. 저장-변경-사용-복원 사이클 - 2 // print the text TextOut(hdc,0,0,”I’m the red text!”,strlen(“I’m the red text!”)); // switch background mode to opaque SetBkMode(hdc,OPAQUE); // change text color; no need to save old color SetTextColor(hdc,RGB(0,0,255)); // print the text TextOut(hdc,0,0,”I’m the blue text!”,strlen(“I’m the blue text!”)); // restore the old colors SetTextColor(hdc,old_text_color); SetBkColor(hdc,old_back_color); // release dc back ReleaseDC(hwnd, hdc);

  40. TEXTMETRIC 검색하기 • 윈도우즈는 가변피치 폰트를 사용한다 • 텍스트 문자열의 폭과 높이를 정확하게 아는 것은 어려운 일이다.

  41. TEXTMETRIC structure typedef struct tagTEXTMETRIC { LONG tmHeight; // * the height of the font LONG tmAscent; // the ascent of the font LONG tmDescent; // the descent of the font LONG tmInternalLeading; // the internal leading LONG tmExternalLeading; // the external leading LONG tmAveCharWidth; // * the average width LONG tmMaxCharWidth; // * the maximum width LONG tmWeight; // the weight of the font LONG tmOverhang; // the overhang of the font LONG tmDigitizedAspectX; // the average x-aspect ratio LONG tmDigitizedAspectY; // the average y-aspect ratio BCHAR tmFirstChar; // * first character font defines BCHAR tmLastChar; // * last character font defines BCHAR tmDefaultChar; // used when desired char not in set BCHAR tmBreakChar; // the break character BYTE tmItalic; // is this an italic font BYTE tmUnderlined; // is this an underlined font BYTE tmStruckOut; // is this a strikeout font BYTE tmPitchAndFamily;//family and technology BYTE tmCharSet; // what is the character set } TEXTMETRIC;

  42. GetTextMetrics() BOOL GetTextMetrics( HDC hdc, // handle of device context LPTEXTMETRIC lptm); // ptr to text metrics struct TEXTMETRIC tm; // holds the data // get the textmetrics GetTextMetrics(hdc,&tm); // use tm data to center a string given the horizontal // width of screen is WINDOW_WIDTH int x_pos = WINDOW_WIDTH - strlen(“Center This String”)*tm.tmAveCharWidth/2; // print the text at the centered position TextOut(hdc,x_pos,0,”Center This String”, strlen(“Center This String”));

  43. 작은 글자는 무엇으로 만들어지는가? • 높이: 문자의 전체 높이를 나타내는 픽셀 수 • 기준선: 참고. 보통 대문자의 바닥. • 어센트: 기준선에서 액센트 표시가 위치하는 상단까지의 픽셀 수. • 디센트: 기준선에서 소문자의 바닥까지의 픽셀 수. • 내부 간격: 액센트 표시를 위한 픽셀 수. • 외부 간격: 문자 위의 다른 문자까지의 픽셀 수.

  44. 각종 모양 그리기 • 점 • 선 • 원, 타원 • 곡선 • 다각형 • 비트맵 • 메타파일(더 기본적인 다른 명령들의 디지타이즈된 기록들 - 다시 볼 수 있는 명령어 목록 같은 것)

  45. 펜으로 그리기 • 펜은 외곽선 객체(선, 곡선, 채워지지 않은 사각형)를 그리는 데 사용되는 객체 • 색상: 표준 RGB 색상 • 스타일: 선이 그려지는 방법 - 실선, 점선 등 HPEN pen_1; // a handle to a pen // 시스템 pen 이용 pen_1 = (HPEN)GetStockObject(WHITE_PEN); // 자신만의 pen 만들기 HPEN CreatePen(int fnPenStyle, // pen style int nWidth, // pen width COLORREF crColor); // pen color

  46. 펜의 스타일 HPEN red_pen = CreatePen(PS_SOLID, 0, RGB(255,0,0)); HPEN green_pen = CreatePen(PS_SOLID, 0, RGB(0,255,0)); HPEN blue_pen = CreatePen(PS_SOLID, 0, RGB(0,0,255));

  47. 펜을 사용 • 장치 컨텍스트안에 펜을 선택하도록 SelectObject() 함수를 사용 HGDIOBJ SelectObject(HDC hdc, // handle of device context HGDIOBJ hgdiobj); // handle of object // select the red pen in and save old one HPEN old_pen = (HPEN)SelectObject(hdc, red_pen); // code to draw with the pen goes here

  48. Delete Pen // delete all the objects // which is usually done at end of program in WM_DESTROY DeleteObject(red_pen); DeleteObject(green_pen); DeleteObject(blue_pen);

  49. 필요한 브러시로 작업하기 • 브러시는 그려진 다른 객체의 내부를 칠하는 데 사용 • 단색(solid) 브러시, 패턴 브러시나 비트맵 이미지 브러시 등을 생성할 수 있다. • 브러시의 핸들은 HBRUSH이고 • 펜을 사용하는 것처럼 GetStockObject()로 다음과 같이 브러시를 불러올 수 있다 HBRUSH brush_1; // a brush hbrush_1 = (HBRUSH)GetStockObject(WHITE_BRUSH);

  50. 브러시 패턴 HBRUSH blue_brush = CreateSolidBrush(RGB(0,0,255)); HBRUSH CreateHatchBrush(int fnStyle, // hatch style COLORREF clrref);// color value Patterns: • HS_BDIAGONAL • HS_CROSS • HS_DIAGCROSS • HS_FDIAGONAL • HS_HORIZONTAL • HS_VERTICAL

More Related