윈도우프로그래밍 Visual C++ 2010 MFC Programming 4 장. 화면출력
GDI 와 DC GDI(Graphics Device Interface) 윈도우운영체제에서그래픽출력을담당하는부분 장치독립성및멀티태스킹지원 운영체제의하위시스템중하나로 DLL 로존재 응용프로그램의요청을받아서실제출력장치에대한출력을담당 O/S 응용프로그램 GDI 장치출력장치드라이버 ( 화면, 프린터등 ) 장치독립적 장치의존적 2
GDI 와 DC DC (Device Context) GDI 가생성하고관리하는구조체데이터 응용프로그램은 DC 를통해데이터를 GDI 에전달하여그래픽출력 응용프로그램 DC GDI 장치드라이버 출력장치 ( 화면, 프린터등 ) 3
화면출력방법 SDK 윈도우운영체제에게 DC 를요청한다. 운영체제로부터받은 DC 핸들을사용하여출력을한다. 운영체제에게 DC 사용이끝났음을알린다. HDC hdc; // DC handle hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 100, 100, str, lstrlen(str)); EndPaint(hwnd, &ps); 4
화면출력방법 MFC DC 객체를생성한다. 객체의멤버함수를호출하여출력한다. CPaintDC dc; dc.textout(100, 100, str); DC 객체의생성및출력을지원하는클래스 CDC 클래스 5
CDC 클래스 계층도 DC 객체의생성을지원하는자식클래스 클래스이름 CPaintDC CClientDC CWindowDC 용도 client 영역에출력할때 (WM_PAINT 메시지핸들러내에서만사용 ) client 영역에출력할때 (WM_PAINT 메시지핸들러를제외한다른모든곳에서사용 ) 윈도우의전체영역 (client 영역 + non-client 영역 ) 에출력할때 CMetaFileDC Metafile 에출력할때 6
CDC 클래스 객체생성 CPaintDC 사용예 void CChildView::OnPaint() { CPaintDC dc(this); //... } CClientDC 사용예 void CChildView::OnLButtonDown(UINT nflags, CPoint point) { CClientDC dc(this); //... } 7
CDC 클래스 객체생성 CWindowDC 사용방법 CPaintDC, CClientDC 클래스와동일 원점위치 (0, 0) CWindowDC (0, 0) CPaintDC, CClientDC 8
WM_PAINT 메시지 윈도우 O/S 에서자동발생 윈도우가생성될때 윈도우의크기가변경될때 최소화또는최대화되었을때 다른윈도우가가렸다가드러날때 응용프로그램에서강제발생 void CWnd::Invalidate (BOOL berase = TRUE); void CWnd::InvalidateRect (LPCRECT lprect, BOOL berase = TRUE); 9
WM_PAINT 메세지 WM_PAINT 메시지처리 HelloSDK HelloMFC case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 100, 100, str, lstrlen(str)); EndPaint(hwnd, &ps); return 0; void CMainFrame::OnPaint() { CPaintDC dc(this); dc.textout(100, 100, msg, lstrlen(msg)); } 10
실습 4-1. CPaintDC void CChildView::OnPaint() { CPaintDC dc(this); dc.rectangle(0, 0, 200, 100); dc.ellipse(200, 100, 500, 200); }
실습 4-2. CClientDC void CChildView::OnLButtonDown(UINT nflags, CPoint point) { CClientDC dc(this); dc.rectangle(point.x-20, point.y-20, point.x+20, point.y+20); } void CChildView::OnRButtonDown(UINT nflags, CPoint point) { CClientDC dc(this); dc.ellipse(point.x-20, point.y-20, point.x+20, point.y+20); }
CDC 클래스 - 그리기함수 점찍기 이름 GetPixel() SetPixel() SetPixelV() 기능 화면의특정위치에해당하는점의색을얻는다. 화면의특정위치에원하는색의점을찍으며원래의점의색을리턴한다. SetPixel 과기능은동일하지만 SetPixel 함수와달리원래의점의색을리턴하지않으므로속도가더빠르다. 13
CDC 클래스 - 그리기함수 선그리기 이름 MoveTo() LineTo() 기능 현재위치를옮긴다. 현재위치로부터특정위치까지선을그린후현재위치를갱신한다. 도형그리기 이름 기능 Rectangle() 직사각형을그린다. Ellipse() 직사각형에내접하는타원을그린다. RoundRect() 테두리가둥근직사각형을그린다. Polygon() POINT 구조체배열로전달된점들을차례로이어서다각형을그린다. 14
CDC 클래스 - 텍스트함수 텍스트출력함수 이름 TextOut() DrawText() SetTextColor() SetBkColor() SetTextAlign() 기능특정위치에문자열을출력한다. 사각형을기준으로문자열을출력한다. 문자의색을바꾼다. 문자의배경색을바꾼다. 기준위치에대한문자열의정렬방식을정한다. 15
실습 4-5. 점찍기 void CChildView::OnPaint() { CPaintDC dc(this); for(int x=0; x<256; x++) for(int y=0; y<256; y++) dc.setpixelv(x, y, RGB(x, y, 0)); }
실습 4-6. 선그리기 void CChildView::OnPaint() { CPaintDC dc(this); // 클라이언트영역의좌표를얻는다. CRect rect; GetClientRect(&rect); // 수평선과수직선을그린다. dc.moveto(0, rect.bottom/2); dc.lineto(rect.right, rect.bottom/2); dc.moveto(rect.right/2, 0); dc.lineto(rect.right/2, rect.bottom); // 마름모꼴을그린다. POINT points[] = { {rect.right/2, 0}, {rect.right, rect.bottom/2}, {rect.right/2, rect.bottom}, {0, rect.bottom/2}, {rect.right/2, 0} }; dc.polyline(points, 5); }
실습 4-7. 텍스트출력하기 void CChildView::OnPaint() { CPaintDC dc(this); CRect rect; GetClientRect(&rect); dc.settextcolor(rgb(255, 0, 0)); // 글자를빨간색으로설정 dc.setbkcolor(rgb(255, 255, 0)); // 배경을노란색으로설정 dc.drawtext(cstring("drawtext 함수를연습합니다. [1]"), &rect, 0); dc.drawtext(cstring("drawtext 함수를연습합니다. [2]"), &rect, DT_CENTER DT_VCENTER DT_SINGLELINE); } dc.settextalign(ta_center); // 가운데정렬방식으로변경 dc.settextcolor(rgb(0, 0, 255)); // 글자를파란색으로설정 dc.setbkcolor(rgb(0, 255, 0)); // 배경을초록색으로설정 dc.textout(rect.right/2, 3*rect.bottom/4, CString("TextOut 함수를연습합니다."));
CDC 클래스 - Mapping Mode 매핑모드단위 x 축 y 축 MM_TEXT 1 픽셀 +x +y MM_LOMETRIC 0.1 mm +x -y MM_HIMETRIC 0.01 mm +x -y MM_LOENGLISH 0.01 인치 +x -y MM_HIENGLISH 0.001 인치 +x -y MM_TWIPS 1/1440 인치 +x -y MM_ISOTROPIC 사용자정의 ( 가로, 세로길이동일 ) 사용자정의 사용자정의 MM_ANISOTROPIC 사용자정의사용자정의사용자정의 19
매핑모드 MM_TEXT Default mode 단위 : pixel 방향 : 오른쪽 +X, 윗쪽 +Y 원점 : 우상단점 장치 (screen) 의존적 장치좌표로사용
매핑모드 MM_LOMETRIC~MM_TWIPS 단위 : mm / inch 등 방향 : 오른쪽 +X, 아래쪽 +Y 원점 : 우상단점 장치 (screen) 독립적 논리좌표로사용
실습 4-8. 매핑모드 1 void CChildView::OnPaint() { CPaintDC dc(this); dc.setmapmode(mm_lometric); // 매핑모드변경 dc.rectangle(0, 0, 1000, -500); dc.setmapmode(mm_himetric); // 매핑모드변경 dc.ellipse(0, 0, 10000, -5000); }
실습 4-9. 매핑모드 2 void CChildView::OnPaint() { CPaintDC dc(this); CRect rect; GetClientRect(&rect); dc.setmapmode(mm_anisotropic); dc.setwindowext(100, 100); dc.setviewportext(rect.width(), rect.height()); dc.roundrect(0, 0, 100, 100, 50, 50); dc.drawedge(crect(20, 20, 80, 80), BDR_SUNKENINNER BDR_RAISEDOUTER,BF_RECT); } MM_ANISOTROPIC => MM_ISOTROPIC
CDC 클래스 - 좌표변환 스크린좌표와클라이언트좌표 스크린좌표의원점 클라이언트좌표의원점 24
CDC 클래스 - 좌표변환 좌표변환함수 클라이언트좌표 DPtoLP LPtoDP 논리좌표 장치좌표 ScreenToClient ClientToScreen 스크린좌표 void CDC::LPtoDP(LPPOINT lppoints, int ncount = 1); void CDC::DPtoLP(LPPOINT lppoints, int ncount = 1); void CWnd::ScreenToClient(LPPOINT lppoint); void CWnd::ClientToScreen(LPPOINT lppoint); 25
CDC 클래스 - 속성함수 속성 초기값 속성을얻는함수 속성을변경하는함수 텍스트색상 검정색 GetTextColor() SetTextColor() 배경색상 흰색 배경모드 OPAQUE 매핑모드 MM_TEXT 그리기모드 R2_COPYPEN 현재위치 (0, 0) 펜 BLACK_PEN 브러시 WHITE_BRUSH 폰트 SYSTEM_FONT 비트맵 없음 팔레트 없음 영역 없음 GetBkColor() GetBkMode() GetMapMode() GetROP2() GetCurrentPosition() SelectObject() SelectObject() SelectObject() SelectObject() SelectPalette() SelectObject() SetBkColor() SetBkMode() SetMapMode() SetROP2() MoveTo() SelectObject() SelectObject() SelectObject() SelectObject() SelectPalette() SelectObject() 26
CDC 클래스 - 그리기모드 그림을그릴때사용하는색상 (S) 이스크린의원래색상 (D) 과섞이는방법정의 그리기모드 연산 그리기모드 연산 R2_NOP D = D R2_NOT D = ~D R2_BLACK D = BLACK R2_WHITE D = WHITE R2_COPYPEN D = S R2_NOTCOPYPEN D = ~S R2_MERGEPENNOT D = ~D S R2_MASKPENNOT D = ~D & S R2_MERGENOTPEN D = ~S D R2_MASKNOTPEN D = ~S & D R2_MERGEPEN D = D S R2_NOTMERGEPEN D = ~(D S) R2_MASKPEN D = D & S R2_NOTMASKPEN D = ~(D & S) R2_XORPEN D = S ^ D R2_NOTXORPEN D = ~(S ^ D) 27
실습 4-10. 배경모드변경하기 void CChildView::OnPaint() { CPaintDC dc(this); dc.setbkmode(opaque); // 이줄을주석처리해도결과는같음 dc.textout(100, 50, CString(" OPAQUE 모드 [1] ")); dc.setbkmode(transparent); dc.textout(100, 100, CString(" TRANSPARENT 모드 ")); } dc.setbkmode(opaque); dc.setbkcolor(rgb(0, 255, 0)); // 배경을초록색으로설정 dc.textout(100, 150, CString(" OPAQUE 모드 [2] "));
GDI 객체 GDI 객체 GDI 에서출력할때사용하는도구 종류및클래스 GDI 객체 용도 클래스이름 Pen 선을그릴때 CPen Brush 면의내부를채울때 CBrush Font 문자를출력할때 CFont Bitmap 픽셀의집합으로이루어진그림을다룰때 CBitmap Palette 출력될색의집합을다룰때 CPalette Region 다양한형태의면을정의할때 CRgn 29
GDI 객체 클래스계층도 30
GDI 객체 GDI 객체사용방법 1 GDI 객체생성 2 생성된 GDI 객체를 DC 에선택하고, 이전에선택되어있던 GDI 객체의주소저장 CDC::SelectObject() 사용 3 GDI 함수를사용하여출력 4 이전의 GDI 객체를 DC 에선택하여, 현재의 GDI 객체선택해제 CDC::SelectObject() 사용 5 GDI 객체소멸 31
GDI 객체 - Pen 생성방법 // 방법 1 CPen pen(ps_solid, 2, RGB(255, 0, 0)); // 방법 2 CPen pen; pen.createpen (PS_SOLID, 2, RGB (255, 0, 0)); 펜스타일 32
GDI 객체 - Pen 사용예 1 CPaintDC dc(this); CPen pen(ps_solid, 1, RGB(0, 0, 255)); // 펜객체생성 CPen *poldpen = dc.selectobject(&pen); //DC 연결, 기존펜저장 dc.rectangle(100, 100, 200, 200); dc.selectobject(poldpen); // 기존펜으로복귀 사용예 2 CPaintDC dc(this); CPen pen(ps_solid, 1, RGB(0, 0, 255)); dc.selectobject(&pen); dc.rectangle(100, 100, 200, 200); 33
실습 4-11. 펜사용하기 void CChildView::OnPaint() { CPaintDC dc(this); // 다양한펜종류를연습한다. int npenstyle[] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFRAME}; TCHAR *PenStyle[] = {_T("PS_SOLID"), _T("PS_DASH"),_T("PS_DOT"), _T("PS_DASHDOT"), _T("PS_DASHDOTDOT"), _T("PS_NULL"), _T("PS_INSIDEFRAME")}; dc.settextalign(ta_baseline); for(int i=0; i<sizeof(npenstyle)/sizeof(npenstyle[0]); i++){ CPen pen(npenstyle[i], 1, RGB(0, 0, 255)); dc.selectobject(&pen); dc.textout(50, 25+i*25, PenStyle[i], lstrlen(penstyle[i])); dc.moveto(200, 25+i*25); dc.lineto(500, 25+i*25); } CPen blackpen(ps_solid, 1, RGB(0, 0, 0)); // 폭 1, 검은색 PS_SOLID 펜 dc.selectobject(&blackpen); dc.rectangle(50, 200, 150, 300); // 폭과높이가 100 인직사각형 CPen pen1(ps_solid, 20, RGB(255, 0, 0)); // 폭 20, PS_SOLID 펜 dc.selectobject(&pen1); dc.ellipse(50, 200, 150, 300); // 지름이 100 인원 } dc.selectobject(&blackpen); dc.rectangle(250, 200, 350, 300); // 폭과높이가 100 인직사각형 CPen pen2(ps_insideframe, 20, RGB(255, 0, 0)); // 폭 20, PS_INSIDEFRAME 펜 dc.selectobject(&pen2); dc.ellipse(250, 200, 350, 300); // 지름이 100 인원
GDI 객체 - Brush 종류 Brush 종류 생성예 Solid ( 속이채워짐 ) CBrush brush(rgb(255, 0, 0)); Hatch ( 교차된평행선무늬 ) Pattern ( 비트맵의반복무늬 ) CBrush brush(hs_diagcross, RGB(255, 0, 0)); CBitmap bitmap; bitmap.loadbitmap(idb_bitmap1); CBrush brush(&bitmap); 35
GDI 객체 - Brush 사용예 1 CPaintDC dc(this); CBrush brush(rgb(255, 0, 0)); CBrush *poldbrush = dc.selectobject(&brush); dc.ellipse(100, 100, 200, 200); dc.selectobject(poldbrush); 사용예 2 CPaintDC dc(this); CBrush brush(rgb(255, 0, 0)); dc.selectobject(&brush); dc.ellipse(100, 100, 200, 200); 36
실습 4-12. 브러시사용하기 void CChildView::OnPaint() { CPaintDC dc(this); // Solid 브러시 CBrush brush1(rgb(255, 0, 0)); dc.selectobject(&brush1); dc.rectangle(50, 50, 200, 200); // Hatch 브러시 CBrush brush2(hs_diagcross, RGB(255, 0, 0)); dc.selectobject(&brush2); dc.ellipse(250, 50, 400, 200); } // Pattern 브러시 CBitmap bitmap; bitmap.loadbitmap(idb_bitmap1); CBrush brush3(&bitmap); dc.selectobject(&brush3); dc.roundrect(450, 50, 600, 200, 50, 50);
GDI 객체 - Font 생성방법 1 CFont 객체생성 2 CFont 객체에대해 Create*() 함수를호출 CFont font; font.createfont(...); // 또는 font.createfontindirect(...); // 또는 font.createpointfont(...); // 또는 font.createpointfontindirect(...); 38
GDI 객체 - Font 사용예 CPaintDC dc(this); CFont font; font.createpointfont(400, "Arial"); dc.selectobject(&font); dc.textout(10, 10, CString("Hello")); 39
GDI 객체 - Stock Object ( 내장객체 ) 윈도우운영체제가미리만들어서제공하는 GDI 객체 이름 BLACK_PEN WHITE_PEN NULL_PEN BLACK_BRUSH DKGRAY_BRUSH GRAY_BRUSH LTGRAY_BRUSH HOLLOW_BRUSH 또는 NULL_BRUSH SYSTEM_FONT 용도 폭이 1 픽셀인검정색펜 폭이 1 픽셀인흰색펜 투명펜 검정색브러시 어두운회색브러시 회색브러시 밝은회색브러시 투명브러시 윈도우운영체제가사용하는폰트예 ) 메뉴, 대화상자,... CDC::SelectStockObject() 함수를사용하여 DC 에연결 40
실습 4-13. 내장객체사용하기 void CChildView::OnPaint() { CPaintDC dc(this); // 클라이언트영역을초록색해치브러시로채운다. CRect rect; GetClientRect(&rect); CBrush brush(hs_cross, RGB(0, 255, 0)); dc.selectobject(&brush); dc.rectangle(&rect); // 경계선이검은색이고내부가비어있는타원을그린다. dc.selectstockobject(black_pen); dc.selectstockobject(null_brush); dc.ellipse(100, 50, 200, 200); } // 경계선이없고내부가밝은회색으로채워진다각형을그린다. dc.selectstockobject(null_pen); dc.selectstockobject(ltgray_brush); POINT points[] = {{250, 50}, {450, 150}, {300, 200}, {250, 150}}; dc.polygon(points, 4);
GDI 객체 - Bitmap 비트맵정보 int CBitmap::GetBitmap (BITMAP* pbitmap) ; typedef struct tagbitmap { int bmtype; int bmwidth; // 비트맵의폭 ( 픽셀단위 ) int bmheight; // 비트맵의높이 ( 픽셀단위 ) int bmwidthbytes; BYTE bmplanes; BYTE bmbitspixel; LPVOID bmbits; } BITMAP; 42
GDI 객체 - 비트맵 비트맵정보출력 CBitmap bitmap; bitmap.loadbitmap(idb_bitmap1); BITMAP bmpinfo; bitmap.getbitmap(&bmpinfo); TRACE(" 가로 = %d, 세로 = %d\n", bmpinfo.bmwidth, bmpinfo.bmheight); 43
GDI 객체 - Bitmap 비트맵출력절차 1 2 3 CDC::CreateCompatibleDC() 함수를이용하여 memory DC (device context) 를만든다. CDC::SelectObject() 함수를이용하여비트맵을 memory DC 에선택한다. CDC::BitBlt() 또는 CDC::StretchBlt() 함수를이용하여화면에출력한다. Memory DC: 메모리의일부를마치화면처럼다룰수있도록운영체제에서제공하는개념 44
GDI 객체 - Bitmap 비트맵출력함수 BOOL BitBlt (int x, int y, int nwidth, int nheight, CDC* psrcdc, int xsrc, int ysrc, DWORD dwrop) ; xsrc ysrc x y nwidth nheight psrcdc (memory device context) (screen device context) 45
GDI 객체 - Bitmap 비트맵출력함수 (cont'd) BOOL StretchBlt (int x, int y, int nwidth, int nheight, CDC* psrcdc, int xsrc, int ysrc, int nsrcwidth, int nsrcheight, DWORD dwrop) ; x y nwidth nheight xsrc ysrc nsrcwidth nsrcheight psrcdc ( 메모리디바이스컨텍스트 ) ( 스크린디바이스컨텍스트 ) 46
실습 4-14. 비트맵출력하기 void CChildView::OnPaint() { CPaintDC dc(this); // 비트맵리소스를로드한후크기정보를얻는다. CBitmap bitmap; bitmap.loadbitmap(idb_bitmap1); BITMAP bmpinfo; bitmap.getbitmap(&bmpinfo); // 메모리 DC 를만든후비트맵을선택해넣는다. CDC dcmem; dcmem.createcompatibledc(&dc); dcmem.selectobject(&bitmap); // 비트맵을화면에출력한다. dc.bitblt(10, 10, bmpinfo.bmwidth, bmpinfo.bmheight, &dcmem, 0, 0, SRCCOPY); dc.stretchblt(10, 100, bmpinfo.bmwidth*4, bmpinfo.bmheight*2, &dcmem, 0, 0, bmpinfo.bmwidth, bmpinfo.bmheight, SRCCOPY); } // 메모리 DC 에그림을그린후다시화면에출력한다. dcmem.rectangle(5, 5, 15, 15); dc.bitblt(350, 10, bmpinfo.bmwidth, bmpinfo.bmheight, &dcmem, 0, 0, SRCCOPY); dc.stretchblt(350, 100, bmpinfo.bmwidth*4, bmpinfo.bmheight*2, &dcmem, 0, 0, bmpinfo.bmwidth, bmpinfo.bmheight, SRCCOPY);