2. 윈도우즈 프로그래밍 출력 1. GDI와 DC 2. 텍스트 출력 3. 그래픽 출력 4. 다양한 텍스트 출력과 그래픽 방법 5. 매핑모드 6. API 메시지와 함수정리 7. 프로그램 연구 8. 실습문제 - 1 -
2. 1. GDI와 DC - 윈도우즈 OS에서는 하드웨어 제조회사들이 마이크로소프트사에서 미리 정해놓은 사양에 따라 해당 하드웨어를 구동할 수 있는 구동 프로그램(디 바이스 드라이버 소프트웨어)를 작성하여 배포 - 프로그래머는 어떤 하드웨어가 현재 시스템에 설치되어 있는지 신경 쓸 필요가 없음 - 비디오카드를 생산하는 제조회사도 자신들의 비디오카드에 대한 드라이 버 소프트웨어를 제공 - 윈도우즈 OS는 출력을 디바이스 드라이버와 통신을 통해서 하게 됨 GDI32.DLL GDI32.DLL 디바이스 디바이스 드라이버 드라이버 프린터, 프린터, 화면 화면 등 그래픽 함수들과 객체들이 정의되어 있음 ex) 네모 하나 그려주세요 >> GDI(Graphic Device Interface) - GDI는 선 그리기, 컬러 관리와 같은 그래픽 함수들을 구현하는 일을 담 당하는 윈도우즈의 구성요소 - 디스플레이, 프린터, 기타 장치에 대한 그래픽 출력을 위하여 응용 프로 그램이 사용할 수 있는 함수와 그에 관련된 구조를 제공 - 이를 이용하여 직선, 곡선, 다각형, 텍스트, 비트맵(bitmap) 이미지를 구 현할 수 있다. - GDI와 관련된 파일은 윈도우즈의 시스템 폴더 밑에 있는 "GDI32.DLL" 파일이다. - GDI32.DLL에는 GDI관련 함수들과 객체들이 정의되어 있다. - 2 -
>> GDI객체와 관련 MFC - 펜 : 선 그리기(CPen) - 브러시 : 영역 채우기(CBrush) - 폰트 :글꼴(CFont) - 팔레트(CPalette) - 리전(CRgn) - 비트맵(CBitmap) >> 윈도우즈에서 출력하는 방법 - WM_PAINT메시지 밑에서 - 출력하고자 하는 DC핸들 얻기 - 출력하기 - 해당 DC소멸 >> DC(Device Context) - 윈도우즈는 매우 강력한 그래픽 기능을 제공한다. - 화면 출력하는 방법을 아주 세세한 부분까지 프로그래머가 제어할 수 있 다. - 선이나 글자를 하나 출력하더라도 색깔, 두께, 모양, 위치 등 그것을 어 떻게 출력할 것인가에 대한 수많은 옵션을 설정할 수 있다. - 세세하게 제어할 수 있는 장점이 있지만 모든 옵션을 일일이 설정해야 하는 번거로움이 따르게 된다. - 그래서 등장한 개념이 바로 DC(Device Context)이다. >> DC와 DC핸들 - DC는 그래픽과 관련된 모든 옵션을 모아놓은 구조체이다. - 그냥 간단히 출력하고자 하면 디폴트로 설정된 DC를 이용하여 바로 출 력을 하면 되고, 보다 세밀한 출력을 하고 싶은 경우에만 관련 옵션을 변경한 후에 출력을 한다. - 윈도우즈에서는 출력장치에 무엇인가를 출력하기 위해서는 반드시 DC 가 필요하다. - 보통 해당 DC핸들을 얻은 후 출력을 한다. - 3 -
- 화면에 출력을 하려면 화면에 대한 DC핸들을 얻어야 하며, 프린터로 출 력하려면 프린터 DC핸들을 얻어야 한다. - 한 화면에서도 윈도우마다 DC를 가지고 있다. - DC핸들은 출력대상을 나타내는 구분 번호라고 생각하면 쉽다. - 모든 GDI함수들은 첫 번째 인자로 DC핸들을 필요로 한다.. LineTo(hdc, 30, 50);. TextOut(hdc, 20, 50, "소프트",6);. Rectangle(hdc,10,10,50,50); >> 윈도우즈에서 제공하는 DC - 화면출력을 위한 디스플레이 DC - 프린터나 플로터 출력을 위한 프린터 DC - 비트맵 출력을 위한 메모리 DC - 디바이스 정보를 얻기 위한 정보 DC - Structure that defines a set of graphic objects and their attributes, and the graphic modes that affect output. In addition, the device context (DC) refers to a physical output device-its name, device driver, and other attributes. GDI function call parameters contain a handle to a DC to include the attributes of the specified device. There are four types of DC: display (supports drawing operations on a video display terminal), printer (supports drawing operations on a printer or plotter), memory (supports drawing operations on a bitmap), and information (supports retrieval of device data.) >> 윈도우즈에서 출력은 WM_PAINT메시지에서 하세요!! - 윈도우의 크기가 변경되었을 때나 다른 윈도우에 가려져 있다가 드러날 때 등 화면에 출력된 결과가 깨질 수 있다. - OS는 깨진 화면을 복구해주지 않는다. - 단지 OS는 화면이 깨질 때 마다 WM_PAINT메시지를 발생시켜준다. - 그래서 출력은 반드시 WM_PAINT메시지 아래에서 해야한다!! - 그래야 화면이 깨질 때 마다 WM_PAINT메시지가 발생하고 그 아래에 작 성한 소스가 다시 실행되어 화면이 복구된다!! - 화면이 깨지지 않는 것 같지만 사실은 깨질 때마다 열심히 다시 그리는 것이다!! - 4 -
>> WM_PAINT 메시지가 발생하는 경우 - 클라이언트 영역이 다시 그려져야 할 필요가 있을 때 윈도우즈 OS가 보 내는 메시지로 대부분의 출력은 이 메시지 처리부에서 작성해야 한다. - 윈도우의 클라이언트 영역 중 일부가 무효화(invalid)되면 OS가 이 메시 지를 큐에 넣어준다. - 다음과 같은 경우에 OS는 WM_PAINT메시지를 프로그램에 전달한다.. 윈도우가 처음 생성되었을 때. 윈도우의 위치가 이동되었을 때. 윈도우의 크기가 변경되었을 때. 최대, 최소화되었을 때. 다른 윈도우에 가려져 있다가 드러날 때. 파일로부터 데이터를 출력할 때. 출력된 데이터의 일부분을 스크롤, 선택, 변화시킬 때. InvalidateRect(), InvalidateRgn()함수를 호출하여 강제로 화면을 무효화시킬 때 화면의 그래픽 일부가 사라져서 다시 출력해야 할 필요가 있는 영역을 무효화 (invalid) 영역이라 하고 이러한 경우를 화면이 무효화되었다고 한다. >> WM_PAINT 메시지의 특징 - 이 메시지를 받았을 때 해당 프로그램은 화면 복구를 위해 클라이언트 영역 전체 또는 무효화된 부분만 다시 그려야 한다. - OS는 화면이 무효화될 때 클라이언트 영역을 복구해 주지 않는 대신에 이 메시지를 보내 줌으로써 해당 프로그램에게 다시 그려야 할 시점을 알려 준다. - 따라서 클라이언트 영역에 출력한 정보는 모두 저장해 두어야 복구가 가 능하다. - WM_PAINT메시지는 모든 메시지 중에서 우선 순위가 가장 낮다. - GetMessage()함수는 메시지 큐에 WM_PAINT메시지가 있더라도 다른 메시지가 대기중이면 그 메시지를 먼저 처리한다. - WM_PAINT메시지는 큐에 대기중인 다른 메시지가 없고 무효화 영역이 존재할 때만 윈도우 프로시저로 보내진다. - WM_PAINT메시지는 한번에 하나만 메시지 큐에 들어갈 수 있다. - 만약 무효화 영역이 생겼는데 WM_PAINT메시지가 이미 메시지 큐에 있 으면 기존의 무효화 영역과 새 무효화 영역의 합으로 새로운 무효화 영 역이 설정된다. - 5 -
>> WM_PAINT 메시지에서 그리기 - 해당 윈도우 프로시저에서 이 메시지를 처리하지 않으면 이 메시지는 DefWindowProc()함수가 처리한다. - 이 함수는 무효영역을 모두 유효화(valid)하며 다시 그리기는 하지 않는 다. - 만약 비 클라이언트 영역도 그려져야 한다면 WM_NCPAINT메시지를 전 달하며, 배경을 지워야 한다면 WM_ERASEBKGND메시지를 전달한다. - WM_PAINT메시지에서 그리기를 할 때는 BeginPaint()와 EndPaint()함 수를 사용해야 한다. - 이 두 함수는 WM_PAINT메시지 내에서만 사용되며 다시 그려야 할 영역 에 대한 정확한 좌표를 조사하며 무효영역을 유효화하고 캐럿을 숨기거 나 배경을 지우는 등의 꼭 필요한 동작을 한다. - 6 -
2.2. 텍스트 출력 - 윈도우즈에서 출력하기 위해서는 WM_PAINT 메시지 처리부에서 관련 소스를 작성해야 한다. - 그렇지 않으면 윈도우의 크기를 변경하거나 다른 윈도우에 의해서 가려 졌을 경우 화면이 복구되지 않는다. - 화면에 출력을 위해서는 3장의 예제 3.2의 WndProc()함수의 switch case문에 다음과 같은 case문을 만들고 그 밑에 필요한 출력코드를 작 성하면 된다. - switch ( umsg ) { case WM_PAINT: 이 부분에 출력코드 작성 : >> DC를 얻고 해제하는 방법 - 출력을 하기 위해서는 제일 먼저 출력대상에 대한 DC핸들을 얻어야 한 다 - 출력이 끝났으면 반드시 해제하여야 한다. - DC는 GDI모듈의 내부 스택을 많이 사용하기 때문에 사용 후 반드시 해 제해야 한다. - DC를 얻고 해제하는 방법은 다음과 같다.. BeginPaint()와 EndPaint():WM_PAINT메시지와 함께 사용. GetDC()와 ReleaseDC():잠시 출력할 때 사용. CreateDC() 와 DeleteDC():DC 를 만들어 사용. GetWindowDC() 와 ReleaseDC(): 비클라이언트 영역을 그리고자할 때 WM_NCPAINT 메시지와 함께 사용. CreateDC() 와 DeleteDC() : DC에 출력하지 않고 정보만 얻고자 할 때 사용. CreateCompatibleDC()와 DeleteDC(): 이미 있는 DC 와 같은 또 하나의 DC 만들 때 사용. 보통 디스플레이를 이용한 메모리 DC를 만들 때 사용 - 7 -
DC를 얻고 해제하는 방법 1: >> BeginPaint()와 EndPaint() - 이 함수들은 WM_PAINT메시지 처리부분에서만 사용하며 그 사용법은 다음과 같다. - HDC hdc PAINTSTRUCT ps case WM_PAINT: hdc=beginpaint(hwnd, &ps); 이 부분에 출력에 관련된 코드 작성 EndPaint(hWnd, &ps); - BeginPaint()함수는 DC를 할당하고 갱신된 영역에 대한 정보를 PAINTSTRUCT구조체형으로 반환하는 함수이다. - PAINTSTRUCT구조체형의 변수 ps가 call by reference로 반환됨을 볼 수 있다. >> BeginPaint함수 - 그리기를 위해 DC핸들을 리턴한다. 이 핸들은 PAINTSTRUCT형 구조체 의 첫 번째 멤버 hdc에도 대입된다. 또한 캐럿이 있으면 캐럿을 숨기 며, 무효화 영역이 배경을 지우도록 요청하면 WM_ERASEBKGND메시 지를 보내 배경을 지우도록 한다. 또한 WM_NCPAINT메시지를 보내 비 클라이언트 영역을 그리도록 한다. DC핸들을 얻는 GetDC()함수는 클 리핑 영역 계산이나 무효화 영역 유효화를 해 주지 않으므로 WM_PAINT에서는 사용할 수 없다. - HDC BeginPaint( HWND hwnd, // handle to window LPPAINTSTRUCT lppaint // pointer to structure for paint information ); - 인자값 hwnd는 그리기를 할 윈도우 핸들로 윈도우 프로시저의 첫번째 인자로 전 달된 hwnd 핸들을 넘겨주면 된다. lppaint는 그리기 정보를 call by reference로 리턴받기 위한 구조체이다. - 리턴값 DC핸들을 리턴해 준다. 어떠한 DC도 얻을 수 없어서 에러가 발생하면 - 8 -
NULL을 리턴한다. >> EndPaint 함수 - WM_PAINT메시지 내에서 DC를 반환하며 그리기를 종료하기 위해 사용 된다. BeginPaint()함수와 항상 쌍을 이루어 사용되며 캐럿을 다시 화 면으로 출력해 주는 역할을 한다. - BOOL EndPaint( HWND hwnd, // handle to window CONST PAINTSTRUCT *lppaint // pointer to structure for paint data ); - 인자 값 hwnd는 그리기를 한 윈도우의 핸들이며, lppaint는 그리기 정보를 가지 고 있는 PAINTSTRUCT형 구조체의 포인터로 BeginPaint()함수에서 사용한 변수를 쓰면 된다. - 리턴값 항상 TRUE를 리턴한다. >> 구조체 COLORREF - 색깔을 지정할 때 많이 사용 - 컴퓨터에서 사용하는 색은 빛의 삼원색인 적색(Red), 녹색(Green), 청 색(Blue)을 각각 8비트로 표현한다(RGB). - COLORREF는 이 RGB값을 32비트로 표현한다. - R값이 255이면 적색이 최대이고 0이면 최소이다. - R, G, B값이 모두 255이면 하얀색이고 0이면 검정색이 된다. - RGB값이 같은 256가지((0,0,0) (255,255,255))를 그레이레벨(Gray level)이라 한다. - 녹색을 만들려고 하면 COLORREF형 변수 color에 RGB매크로를 이용 하여 다음과 같은 값을 대입하면 된다. - COLORREF color=rgb(0,255,0); - RGB매크로는 BYTE단위로 각 인자는 R, G, B의 크기를 나타내다. - 9 -
COLORREF RGB( BYTE bred, // red component of color BYTE bgreen, // green component of color BYTE bblue // blue component of color ); 실 습 1) - 다음과 같이 출력하는 프로그램을 작성하시오. - 윈도우의 크기를 변경시키거나, 윈도우의 일부가 가려졌다 다시 보일 경 우 출력이 어떻게 되는지 확인해 보고 그 이유는? 시작좌표=(20픽셀,20픽셀) >> 소스 중 WM_PAINT메시지부 case WM_PAINT: // 화면을 다시 그려야 할 때마다 반복 실행됨 { // BeginPaint() 함수를 이용하여, DC를 얻은 뒤 // TextOut() 함수를 이용하여 문자열을 출력한다. char *szmessage = "윈도우야 안녕!"; PAINTSTRUCT ps HDC hdc hdc= BeginPaint(hWnd, &ps); TextOut(hdc, 20, 20, szmessage, strlen(szmessage)); TextOut(hdc, 20, 50, "소프트",6); EndPaint(hWnd, &ps); } break; - 10 -
DC를 얻고 해제하는 방법2: GetDC()와 ReleaseDC() - WM_PAINT메시지와 상관없이 언제든지 DC핸들을 얻고 해제하는 함수 이다. - 그래서 일시적인 출력을 할 경우에만 사용한다. - 즉, 화면에 감추어져 있다가 나타나거나 윈도우의 크기가 변하거나 프로 그램 내에서 InvalidateRect()나 InvalidateRgn()함수를 호출하게 되면, 화면이 무효화되어 WM_PAINT메시지가 발생되어 새로 화면을 갱신하 기 때문에 GetDC()함수와 ReleaseDC()함수를 이용하여 출력한 내용 은 사라지게 된다. - 보통 GetDC()함수와 ReleaseDC()함수는 잠시 출력하는 데이터나 단순 히 DC정보를 얻기 위해서만 사용한다. - 이 두 함수는 다음과 같이 항상 쌍으로 존재해야 한다. - HDC hdc hdc=getdc(hwnd); 이 부분에 출력에 관련된 코드 작성 ReleaseDC(hWnd, hdc); - GetDC()함수는 hwnd가 가리키는 윈도우에 대한 DC핸들을 반환한다. 실습 2) - 마우스 왼쪽 버튼을 누를 때마다 다음과 같이 클릭한 위치에 "안녕!"이라 는 문자열을 출력하는 프로그램을 작성하시오. - 윈도우의 크기를 변경시키거나, 윈도우의 일부가 가려졌다 다시 보일 경 우에 출력이 어떻게 되는지 확인해 보고 그 이유는? 심화 실습 : 출력 문자열 "왼쪽"으로 변경 오른쪽 버튼 누르면 "오른쪽"출력 - 11 -
-HDC hdc case WM_LBUTTONDOWN://WM_PAINT메시지 아님 hdc=getdc(hwnd); TextOut(hdc,LOWORD(lParam),HIWORD(lParam),"안녕!",5); ReleaseDC(hWnd,hdc); break; - 12 -
DC를 얻고 해제하는 방법3: >> CreateDC()와 DeleteDC() - 지금까지는 윈도우 핸들과 함께 해당 DC를 얻었다. - 그러나 DC만 따로 만들 필요가 생긴다. - 예를 들어 모니터 전체 화면의 DC를 얻고자 할 경우로, 이러한 경우에 는 CreateDC()함수와 DeleteDC()함수를 이용하여 다음과 같이 하면 된다. - HDC hdc char *szmessage = "윈도우야 안녕!"; hdc=createdc("display",null,null,null); TextOut(hdc, 100, 100, szmessage, strlen(szmessage)); DeleteDC(hdc); - 13 -
DC를 얻고 해제하는 방법4: >> GetWindowDC()와 ReleaseDC() - 이 함수는 비클라이언트 영역을 그리고자 할 때 WM_NCPAINT메시지와 함께 사용한다. LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { char *szmessage = "윈도우야 안녕!"; switch ( umsg ) { case WM_NCPAINT: hdc=getwindowdc(hwnd); TextOut(hdc, 1, 1, szmessage, strlen(szmessage)); ReleaseDC(hWnd,hdc); break; case WM_DESTROY: PostQuitMessage(0); break; default : return DefWindowProc( hwnd, umsg, wparam, lparam ); } return 0; } Non-client 영역 클라이언트 영역 - 14 -
DC를 얻고 해제하는 기타 방법 - CreateDC()와 DeleteDC() - 이 함수는 DC에 출력하지 않고 정보만 얻고자 할 때 사용한다. - CreateCompatibleDC()와 DeleteDC() - 이미 있는 DC와 같은 또 하나의 DC를 만들 때 사용한다. - 보통 디스플레이를 이용한 메모리 DC를 만들 때, 비트맵을 화면으로 출 력할 때 사용한다. >> 다양한 텍스트 출력 함수 - DrawText() : 박스영역에 출력하는 함수 - ExtTextOut() : 박스영역 및 설정 문자 출력 함수 - TabbedTextOut() : 탭키에 대응하여 문자 출력하는 함수 - SetBkColor() : 배경색 지정하는 함수 - SetBkMode() :새로 출력되는 문자열의 배경을 어떻게 처리할 것인가를 지정하는 함수 - SetTextColor() : 문자의 출력색을 설정하는 함수 - CreateFont() : 폰트 만들 때 사용하는 함수 - 15 -
2.3. 그래픽 출력 2.3.1 점그리기 - 화면에 하나의 점( 픽셀) 을 출력하는데 사용하는 함수는 SetPixel() 이다. - 다음은 (100,50) 좌표에 녹색의 한 점을 찍는 방법이다. - COLORREF crcolor=rgb(0,255,0); SetPixel(hdc, 100, 50, crcolor); - SetPixel(hdc, 100, 50, RGB(0,255,0)); - 픽셀은 그래픽의 최소단위이나 많이 사용하지는 않으며, 특정좌표의 픽셀의 색을 얻고자 하면 GetPixel() 함수를 사용한다. 2.3.2 선그리기 - 선을 그릴 때는 MoveToEx() 함수와 LineTo() 함수를 쌍으로 사용한 다. - MoveToEx() 함수는 시작점으로 그리기 좌표를 이동시키는 기능을 하며 LineTo() 함수는 그 위치까지 선을 그린다. - (10,20) 에서 (30,50) 까지 선을 긋고 싶다면 다음과 같이 두 함수 를 쌍으로 사용하면 된다. - MoveToEx(hdc, 10, 20, NULL); LineTo(hdc, 30, 50); - 16 -
실습 3) 마우스왼쪽 버튼을 누를 때마다 다음과 같이 그 좌표부터 각 방향으로 길이가 50인 선을 그리는 프로그램을 작성하시오. case WM_LBUTTONDOWN: hdc=getdc(hwnd); MoveToEx(hdc,LOWORD(lParam),HIWORD(lParam), NULL); LineTo(hdc,LOWORD(lParam)+50,HIWORD(lParam)+50); ReleaseDC(hWnd,hdc); break; 심화 실습 : 왼쪽버튼은 수직선, 오른쪽버튼은 수평선 출력하는 프로그램 을 작성하시오. - 17 -
실습 4) 실습 3을 WM_PAINT메시지 아래에서 구현하시오. LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { static int x=0,y=0;// 처음 실행시 한번만 초기화 switch ( umsg ) { HDC hdc PAINTSTRUCT ps case WM_LBUTTONDOWN: x=loword(lparam); y=hiword(lparam); InvalidateRect(hWnd,NULL,FALSE); break; case WM_PAINT: hdc=beginpaint(hwnd,&ps); MoveToEx(hdc,x,y, NULL); LineTo(hdc,x+50,y+50); EndPaint(hWnd,&ps); break; case WM_DESTROY: PostQuitMessage(0); break; default : return DefWindowProc( hwnd, umsg, wparam, lparam ); } return 0; } InvalidateRect(hWnd,NULL,TRUE );로 수정한 후 결과를 확인해 보자. 매번 배경을 지우고 출력하므로 가장 최근의 마우스 클릭 위치에만 선이 그려지는 것을 확인할 수 있다. 이 프로그램은 WM_PAINT메시지에서 출력하고 있으므로 화면이 무효화되었을 때 화면을 복구 할까? 그렇지 않다. WM_PAINT메시지에서 출력하고 있지만 마우스 좌표는 가장 최근의 좌표 만 기억하고 있다. 그래서 윈도우의 크기를 변경시킨다든지 하면 가장 최근에 클릭한 위치만 복구됨을 확인할 수 있다. 모든 선을 복구하려면 좌표값을 배열이나 연결 리스트(linked list)에 모두 저장하고 있어야 하 며, 각 위치에 반복해서 출력해주면 된다. - 18 -
>> auto와 static변수의 차이 #include <iostream.h> void sub(); void main() { sub(); sub(); sub(); } void sub() { auto int x=10; static int y=10; cout<<x<<y<<' \n'; x++; y++; } 10 10 10 11 10 12 - auto변수. 함수나 블록을 진입하면 기억영역이 확보되고, 벗어나면 기억 영역은 소거됨. 스택(stack)을 일시적으로 사용. 해당 함수(블록) 내에서만 유효한 지역(local)변수. 생략가능 - static변수. 프로그램이 종료될 때까지 자료를 기억 장소에 유지. 프로그램이 실행될 때 생성되고 프로그램이 종료될 때 시스템에 반환. 처음 실행시 한번만 초기화 - 19 -
2.3.3 도형그리기 - 사각형은 Rectangle()함수를 이용하여 그린다. - BOOL Rectangle(hdc, nleftrect, ntoprect, nrightrect, nbottomrect) - 모서리가 둥근 사각형을 그릴 때는 RoundRect() 함수를 사용한다. - 원을 그리는 함수는 Ellipse(), Arc(), Chord(), Pie() 등이 있다.. Ellipse() 함수는 설정한 사각형 영역에 맞는 원. Arc() 함수는 설정된 영역에 시작좌표에서 끝 좌표까지 원호. Chord() 함수는 현. Pie() 함수 부채꼴 실습 5) 마우스왼쪽 버튼을 누를 때마다 그 좌표부터 각 방향으로 길이가 50인 정사각형을 그리는 프로그램을 작성하시오. 힌트 ) 실습 4 의 소스에서 WM_PAINT 메시지 부분을 아래와 같이 수정. case WM_PAINT: hdc=beginpaint(hwnd,&ps); Rectangle(hdc,x,y,x+50,y+50); EndPaint(hWnd,&ps); break; 실습 6) 마우스왼쪽 버튼을 누를 때마다 그 좌표부터 각 방향으로 길이가 50인 정사각형과 그 영역을 채우는 원을 그리는 프로그램을 작성하시오. case WM_PAINT: hdc=beginpaint(hwnd,&ps); Rectangle(hdc,x,y,x+50,y+50); // 네모 Ellipse(hdc,x,y,x+50,y+50); // 원 EndPaint(hWnd,&ps); break; - 20 -
2.3.4 다양한 텍스트 출력과 그래픽 방법 - 지금까지의 텍스트 출력은 시스템 폰트로, 그래픽은 검은색의 가는 선 으로, 도형의 내부는 흰색으로 채워져서 출력되었다. - 이는 디폴트DC를 사용했기 때문이다. - 그림판 프로그램은 왼쪽, 아래의 도구상자들을 이용해서 다양한 출력을 할 수 있다. - 21 -
2.3.5 맵핑모드 1) GDI객체(object)와 스톡 객체(stock object) - 다양한 출력을 하기 위해서는 그래픽 출력에 사용하는 도구인 GDI객체 (object)에 대해서 알아야한다.. 폰트, 펜, 브러시, 비트맵, 팔레트, 리전 등 - 그래픽을 출력하기 전에 DC 에 이러한 객체를 선택하므로서 다양 한 출력이 가능하다.. 그냥 선을 그리면 검은색 1 픽셀 실선이 그려지지만 빨간색 5 픽셀 점선 펜을 만들어 DC 에 선택한 후 그리면 GDI 는 이 펜을 사용하여 선을 그 리므로 빨간색 5 픽셀 점선이 그려진다. - 윈도우즈에서 기본적으로 제공하는 GDI객체를 스톡 객체(stock object) 라 한다.. OS 가 기본적으로 제공해 주므로 따로 생성하지 않고 사용할 수 있으며 해제하지 않아도 된다.. GetStockObject()함수를 사용하여 해당 스톡 객체 핸들을 얻을 수 있다.. 회색 스톡 브러시를 구해 윈도우 클래스의 바탕 브러시로 지정하는 예 : WndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); 2) GDI객체 생성과 DC에 선택 - GDI객체를 만드는 함수. 펜: CreatePen, CreatePenIndirect. 브러시: CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush. 폰트( 글꼴): CreateFont, CreateFontIndirect. 리전 : CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect. 비트맵: CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection - GDI객체를 DC에 선택하는 함수. HGDIOBJ SelectObject( HDC hdc, // handle to device context HGDIOBJ hgdiobj // handle to object );. hdc 는 DC 핸들이며, hgdiobj 는 DC 에 선택하고자 하는 GDI 객체 핸들이다. 이 객체는 CreateXXX 의 함수로 생성한 GDI 객체나 GetStockObject() 함수로 구한 스톡 객체이다. - 22 -
실습 7) 실습 5의 출력을 정사각형 내부를 회색으로 채워서 그리는 프로그램을 작성하시오. case WM_PAINT: HBRUSH hnewb,holdb hdc=beginpaint(hwnd,&ps); hnewb=(hbrush)getstockobject(gray_brush); holdb=(hbrush)selectobject(hdc,hnewb); Rectangle(hdc,x,y,x+50,y+50); SelectObject(hdc,hOldB); EndPaint(hWnd,&ps); break; SelectObject()함수에 의해 GDI객체를 DC에 선택한다. SelectObject()함수가 반환하는 값은 이전에 선택되어 있던 객체 핸들로 DC의 상태 복구를 위해 holdb변수에 저장한다. 출력하고 난 후에는 SelectObject(hdc,hOldB)를 호출하여 원래의 GDI 객체로 DC의 상태를 복구한다 심화 실습 : 검은색으로 채우기 - 23 -
3) 다양한 그래픽 출력 방법 - 윈도우즈에서 기본적으로 제공하는 GDI객체인 스톡 객체는 따로 생성 할 필요가 없어서 편리하지만 다양하게 그래픽을 하기에는 부족 - 다양한 출력을 위해서는 GDI객체를 만들어서 사용 - GDI객체를 만드는 함수는 앞의 "Create"로 시작하는 함수 - 일반적으로 다양한 그래픽을 하기 위한 절차. 우선 BeginPaint() 나 GetDC() 등의 함수를 이용하여 DC 를 생성. GetStockObject() 로 스톡 객체나 Create 로 시작하는 함수로 GDI 객체를 생성. 만든 GDI 객체를 SelectObject() 함수로 선택하고, 이 함수의 리턴값인 이전 의 GDI 객체를 그리기 작업을 다한 후 DC 를 원상 복구할 목적으로 보관. SetBkColor() 함수로 배경색을 설정하거나 Set 으로 시작하는 함수들을 이용 하여 다양한 설정. GDI 함수를 이용하여 그리기 작업. 그리기 작업이 다 끝난 후에는 보관해놓았던 이전 GDI 객체를 SelectObject() 함수로 선택하여 이전 DC 상태로 복구. 생성한 GDI 객체를 DeleteObject() 함수로 삭제. 생성했던 DC 를 EndPaint() 나 ReleaseDC() 함수로 소멸 1.DC 1.DC 생성:BeginPaint(), 생성:BeginPaint(), GetDC() GetDC() 등 2.스톡/GDI 2.스톡/GDI 객체 객체 생성:GetStockObject(), 생성:GetStockObject(), CreateXXX() CreateXXX() 3.DC에 3.DC에 GDI객체 GDI객체 선택하고 선택하고 이전의 이전의 GDI객체 GDI객체 보관:SelectObject() 보관:SelectObject() 4.배경색, 4.배경색, 전경색 전경색 등을 등을 DC에 DC에 설정 설정 :SetBkColor() :SetBkColor() 등 5.그래픽 5.그래픽 출력: 출력: Rectangle(), Rectangle(), TextOut() TextOut() 등 6.이전 6.이전 DC상태 DC상태 복구: 복구: SelectObject() SelectObject() 7.GDI 7.GDI 객체 객체 소멸: 소멸: DeleteObject() DeleteObject() 8.DC소멸: 8.DC소멸: EndPaint(), EndPaint(), ReleaseDC() ReleaseDC() 등 - 24 -
실습 8) 실습 6의 출력을 정사각형은 굵기 3픽셀인 녹색 실선으로, 원의 내부는 빨간색으로 채워서 그리는 프로그램을 작성하시오. // case WM_LBUTTONDOWN: x=loword(lparam); y=hiword(lparam); InvalidateRect(hWnd,NULL,FALSE); break; // case WM_PAINT: HBRUSH hnewb,holdb HPEN hnewp,holdp 펜 브러시 hdc=beginpaint(hwnd,&ps); hnewp=createpen(ps_solid,3,rgb(0,255,0)); //펜 만들기 holdp=(hpen)selectobject(hdc,hnewp); Rectangle(hdc,x,y,x+50,y+50); SelectObject(hdc,hOldP); DeleteObject(hNewP); //이 줄을 주석처리하면 hnewb=createsolidbrush(rgb(255,0,0)); //브러시 만들기 holdb=(hbrush)selectobject(hdc,hnewb); Ellipse(hdc,x,y,x+50,y+50); SelectObject(hdc,hOldB); DeleteObject(hNewB); EndPaint(hWnd,&ps); break 심화 실습 : 5픽셀 노란색 펜, 파란색 브러시 - 25 -
4) 레스터연산(ROP:Rater OPeration) - 현재 출력된 화면의 그림과 새로 그려지는 그림이 겹쳐질 때 어떻게 출 력될지를 결정 - 디폴트는 R2_COPYPEN으로 새로 그려지는 그림이 기존 그림을 덮어 버림 - ROP를 변경하는 함수. SetROP2(hdc,R2_XORPEN); - 현재 설정된 ROP를 구하는 함수(DC에 설정되어 있는 ROP를 반환). GetROP2() 실습 9) 실습 7의 Rectangle()함수 전에 "SetROP2(hdc,R2_XORPEN);"소스를 추가하여 출력 결과를 확인하시오. - 기존의 사각형과 XOR연산이 되어 겹치는 부분은 반전 - 26 -
5) 모니터 화면의 좌표체계 - 윈도우즈의 좌표체계는 픽셀 단위이다. - 그러나 때로는 이런 픽셀 단위의 좌표 체계가 프로그램에서 응용하기에 부적합할 수도 있다. - 예를 들어 화면(모니터)은 72dpi(dots per inch)의 저해상도이지만 프 린터는 보편적으로 600dpi 이상의 고해상도를 지원한다. - 모니터 화면의 좌표체계는 왼쪽상단이 (0,0)의 원점으로 사용되며, x축 좌표는 오른쪽으로 갈수록 증가하고 y축 좌표는 아래쪽으로 갈수록 증 가한다. - y축의 증가 방향이 수학에서 나오는 2차원 좌표계의 방향과 반대이다. 원점(0,0) x좌 표 증 가 방 향 y좌 표 증 가 방 향 - 27 -
6) 맵핑모드(mapping mode) - 좌표 체계(단위, x축, y축 증가 방향) - 논리적 좌표(logical coordinates)와 물리적 좌표(device coordinates). 논리적 좌표는 윈도우즈의 내부에서 사용되는 좌표를 말한다. : DC 핸들을 인자로 받는 모든 GDI 함수가 사용. 물리적 좌표는 실제 화면이나 프린터에 출력되는 좌표이며 픽셀이나 도트 단위를 사용한다. : 윈도우를 관리하는 함수나 메시지에서 사용하는 좌표 - 윈도우즈가 디폴트로 사용하는 맵핑 모드(MM_TEXT) 에서는 논리 적 좌표와 물리적 좌표가 일치되어 있기 때문에 어떠한 변환도 일어나지 않는다. - 맵핑 모드를 변경하면 화면에 출력되는 실제좌표는 달라진다. - 맵핑 모드 단위 x 증가방향 y 증가방향 MM_TEXT 픽셀 오른쪽 아래쪽 MM_LOMETRIC 0.1mm 오른쪽 윗 쪽 MM_HIMETRIC 0.01mm 오른쪽 윗 쪽 MM_LOENGLISH 0.01인치 오른쪽 윗 쪽 MM_HIENGLISH 0.001인치 오른쪽 윗 쪽 MM_TWIPS 1/1440인치(twip) 오른쪽 윗 쪽 MM_ISOTROPIC 가변 가 변 가 변 MM_ANISOTROPIC 가변 가 변 가 변 - 디폴트 맵핑 모드는 픽셀 단위인 MM_TEXT이며 나머지 맵핑 모드는 밀 리미터나 인치 등의 논리적인 단위를 사용한다. - 맵핑 모드를 변경할 때는 SetMapMode()함수를 사용한다.. int SetMapMode( HDC hdc, int fnmapmode ); - 현재 설정된 맵핑 모드를 알고 싶을 때는 GetMapMode()함수를 사용한 다.. int GetMapMode( HDC hdc ); - 28 -
실습 10 ) cos함수의 2주기를 출력하는 프로그램을 작성하시오. #include <windows.h> #include <math.h> #define PI 3.14159265358979323846 // cos함수 사용 // 매크로 상수 HDC hdc PAINTSTRUCT ps double deg; int y; case WM_PAINT: hdc=beginpaint(hwnd,&ps); SetMapMode(hdc,MM_LOENGLISH); SetViewportOrgEx(hdc,300,300,NULL); Rectangle(hdc,-360,-100,360,100); TextOut(hdc,10,120,"1",1); TextOut(hdc,10,-110,"-1",2); MoveToEx(hdc, -1000, 0,NULL); // x좌표축 그리기 LineTo(hdc, 1000, 0); MoveToEx(hdc,0,-200,NULL); // y좌표축 그리기 LineTo(hdc,0,200); for(deg=-360;deg<360;deg++) { y=(int)(cos(deg*pi/180)*100); //라디안으로 변환 SetPixel(hdc, (int)deg, y,rgb(255,0,0)); } EndPaint(hWnd, &ps); break; >> 심화 실습 : sin은 녹색, tan는 파란색 - 29 -