Visual C++ Programming How to draw 3 Department of Digital Contents Sang Il Park
Outline Review How to draw with MFC 3
Review: Device Context 메타 파일(Metafile)에 출력할 때 CMetaFileDC 윈도우의 전체 영역(클라이언트 영역 + 비 클라이언트 영역)에 출력할 때 CWindowDC 클라이언트 영역에 출력할 때 (WM_PAINT 메시지 핸들러를 제외한 다른 모든 곳에서 사용) CClientDC (WM_PAINT 메시지 핸들러에서만 사용) CPaintDC 용도 클래스 이름
Review: CPaintDC 클래스 오로지 WM__PAINT 메시지 핸들러에서만 사용 CPaintDC 사용 예 OnPaint() CPaintDC 사용 예 void CChildView::OnPaint() { CPaintDC dc(this); // ... }
Review: CClientDC 클래스 WM_PAINT 메시지 핸들러 이외의 부분에서 사용 CClientDC 사용 예 void CChildView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); // ... }
Review: CWindowDC 클래스 CWindowDC 사용 방법 원점 위치 CPaintDC, CClientDC 클래스와 동일 원점 위치 (0, 0) CWindowDC (0, 0) CPaintDC, CClientDC
Review: CMetaFileDC 클래스 GDI 명령어를 저장할 수 있는 파일 CMetaFileDC 사용 방법 CMetaFileDC 객체를 만든 후 CMetaFileDC::Create() 호출 메타 파일 객체를 일반적인 디바이스 컨텍스트 객체로 간주하고 출력 관련 멤버 함수를 호출 CMetaFileDC::Close()를 호출하면 윈도우 운영체제가 내부적으로 메타 파일을 만든 후 메타 파일 핸들(HMETAFILE 타입)을 리턴 CDC::PlayMetaFile()로 메타 파일을 실행
Review: 그리기 함수 (1/3) 점 찍기 COLORREF color = dc.GetPixel (x,y); SetPixel과 기능은 동일하지만 SetPixel 함수와 달리 원래의 점의 색을 리턴하지 않으므로 속도가 더 빠르다. SetPixelV() 화면의 특정 위치에 원하는 색의 점을 찍으며 원래의 점의 색을 리턴한다. SetPixel() 화면의 특정 위치에 해당하는 점의 색을 얻는다. GetPixel() 기능 이름 COLORREF color = dc.GetPixel (x,y); dc.SetPixelV(x,y, RGB(r,g,b));
Review: 그리기 함수 (2/3) 도형 그리기 dc.Rectangle (x1, y1, x2, y2); 사각형에 내접하는 타원을 그린다. Ellipse() 사각형을 그린다. Rectangle() 기능 이름 (x1, y1) dc.Rectangle (x1, y1, x2, y2); dc.Ellipse (x1, y1, x2, y2); (x2, y2) 9
Review: 그리기 함수 (2/3) 창의 사이즈를 알고 싶다? CRect rect; GetClientRect(rect);
Review: 그리기 함수 (3/3) 선 그리기 dc.MoveTo(x1,y1); dc.LineTo(x2,y2); 현재 위치로부터 특정 위치까지 선을 그린 후 현재 위치를 갱신한다. LineTo() 현재 위치를 옮긴다. MoveTo() 기능 이름 (x1,y1) dc.MoveTo(x1,y1); dc.LineTo(x2,y2); (x2,y2)
Review: 텍스트 함수 텍스트 출력 함수 dc.SetTextColor(RGB(255,0,0)); 기준 위치에 대한 문자열의 정렬 방식을 정한다. SetTextAlign() 문자의 배경색을 바꾼다. SetBkColor() 문자의 색을 바꾼다. SetTextColor() 사각형을 기준으로 문자열을 출력한다. DrawText() 특정 위치에 문자열을 출력한다. TextOut() 기능 이름 dc.SetTextColor(RGB(255,0,0)); dc.SetBkColor(RGB(0,255,0)); dc.SetTextAlign(TA_CENTER); dc.TextOut(300,200,“Sejong University”); http://msdn2.microsoft.com/ko-kr/library/e37h9k5s(VS.80).aspx
Review: 매핑 모드 변환 CDC::SetMapMode (MappingMode); +x 매핑 모드 단위 x축 y축 MM_TEXT 1 픽셀 +y MM_LOMETRIC 0.1 mm -y MM_HIMETRIC 0.01 mm MM_LOENGLISH 0.01 인치 MM_HIENGLISH 0.001 인치 MM_TWIPS 1/1440 인치 MM_ISOTROPIC 사용자 정의(가로, 세로 길이 동일) 사용자 정의 MM_ANISOTROPIC
Review: 좌표 변환 좌표 변환 함수 장치 좌표 클라이언트 좌표 스크린 좌표 논리 좌표 ScreenToClient ClientToScreen DPtoLP LPtoDP
How to draw with MFC 3
GDI를 이용하여 그림을 그리는 것 기본값: 색을 바꾸거나 특성을 바꿀 수 없을까? Pen의 특성을 바꾼다 : 선 Brush의 특성을 바꾼다: 면
GDI 객체 (1/3) GDI 객체 종류 GDI에서 출력할 때 사용하는 도구 GDI 객체 용도 클래스 이름 펜 선을 그릴 때 CPen 브러시 면의 내부를 채울 때 CBrush 폰트 문자를 출력할 때 CFont 비트맵 픽셀의 집합으로 이루어진 그림을 다룰 때 CBitmap 팔레트 출력될 색의 집합을 다룰 때 CPalette 영역 다양한 형태의 면을 정의할 때 CRgn
GDI 객체 (2/3) 클래스 계층도
GDI 객체 (3/3) GDI 객체 사용 방법 GDI 객체를 스택에 생성한다. 생성된 GDI 객체를 디바이스 컨텍스트에 선택하고 이전에 선택되어 있던 같은 종류의 GDI 객체의 주소를 저장해둔다(CDC::SelectObject() 사용). GDI 함수를 사용하여 출력을 한다. 이전의 GDI 객체를 디바이스 컨텍스트에 선택함으로써 기존에 선택된 GDI 객체를 선택 해제한다(CDC::SelectObject() 사용). GDI 객체가 범위(Scope)를 벗어나면 소멸자가 자동으로 호출되면서 파괴된다.
GDI 객체 (3/3) 그림을 그리는 순서 (일반적인 경우) Pen을 고른다. Pen을 쥐어준다. 그림을 그린다.
GDI 객체 (3/3) 그림을 그리는 순서 (GDI객체사용) 사용할 객체(pen)를 정의한다. DC에 이 객체를 지정해 준다. (CDC::SelectObject()) 그림을 그린다. 사용할 객체를 선택해제 한다. (이전에 가지고 있던 객체를 임시저장) (이전에 가지고 있던 객체로 환원)
펜 (1/2) 생성 방법 펜 스타일 스타일 폭 색 // 방법 1 CPen pen(PS_SOLID, 2, RGB(255, 0, 0)); // constructor // 방법2 CPen pen; pen.CreatePen (PS_SOLID, 2, RGB (255, 0, 0)); // 초기화함수
펜 (2/2) 사용 예 1 사용 예 2 CPaintDC dc(this); CPen pen(PS_SOLID, 1, RGB(0, 0, 255)); CPen *pOldPen = dc.SelectObject(&pen); dc.Rectangle(100, 100, 200, 200); dc.SelectObject(pOldPen); CPaintDC dc(this); CPen pen(PS_SOLID, 1, RGB(0, 0, 255)); dc.SelectObject(&pen); dc.Rectangle(100, 100, 200, 200);
브러시 (1/2) 종류 브러시 종류 생성 예 솔리드(Solid, 속이 채워짐) CBrush brush(RGB(255, 0, 0)); 해치(Hatch, 교차된 평행선 무늬) CBrush brush(HS_DIAGCROSS, RGB(255, 0, 0)); 패턴(Pattern, 비트맵의 반복 무늬) CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CBrush brush(&bitmap);
브러시 (2/2) 사용 예 1 사용 예 2 CPaintDC dc(this); CBrush brush(RGB(255, 0, 0)); CBrush *pOldBrush = dc.SelectObject(&brush); dc.Ellipse(100, 100, 200, 200); dc.SelectObject(pOldBrush); CPaintDC dc(this); CBrush brush(RGB(255, 0, 0)); dc.SelectObject(&brush); dc.Ellipse(100, 100, 200, 200);
폰트 (1/2) 생성 방법 CFont 객체 생성 CFont 객체에 대해 CreateFont() 함수를 호출 CFont font; font.CreateFont(...); // font.CreateFontIndirect(...); // font.CreatePointFont(...); // font.CreatePointFontIndirect(...);
폰트 (2/2) 사용 예 CPaintDC dc(this); CFont font; font.CreatePointFont(400, "Arial“); dc.SelectObject(&font); dc.TextOut(10, 10, "Hello”);
내장 객체 CDC::SelectStockObject() 함수를 사용하여 디바이스 컨텍스트에 선택한다. 이름 용도 BLACK_PEN 폭이 1 픽셀인 검정색 펜 WHITE_PEN 폭이 1 픽셀인 흰색 펜 NULL_PEN 투명 펜 BLACK_BRUSH 검정색 브러시 DKGRAY_BRUSH 어두운 회색 브러시 GRAY_BRUSH 회색 브러시 LTGRAY_BRUSH 밝은 회색 브러시 HOLLOW_BRUSH 또는 NULL_BRUSH 투명 브러시 SYSTEM_FONT 윈도우 운영체제가 사용하는 폰트 예) 메뉴, 대화상자, ... CDC::SelectStockObject() 함수를 사용하여 디바이스 컨텍스트에 선택한다.
CRgn: 사각형(원)이 아닌 영역 객체 다각형 (Polygon)
CRgn: 사각형(원)이 아닌 영역 객체 사용방법 nStyle: ALTERNATE or WINDING CRgn rgn 점의 배열 점 갯수 style CRgn rgn rgn.CreatePolygonRgn( CPoint * pt, int nNumber, int nStyle) dc.PaintRgn(&rgn); nStyle: ALTERNATE or WINDING
CRgn: 사각형(원)이 아닌 영역 객체 예제 CPaintDC dc(this); CRgn rgn; CPoint ptVertex[5]; ptVertex[0] = CPoint(180,80); ptVertex[1] = CPoint(100,160); ptVertex[2] = CPoint(120,260); ptVertex[3] = CPoint(240,260); ptVertex[4] = CPoint(260,160); rgn.CreatePolygonRgn( ptVertex, 5, ALTERNATE); dc.PaintRgn(&rgn);
비트맵 그림을 dot(pixel)로 표현 하는 것
비트맵: 간단한 비트맵 만들기 리소스 뷰에서 리소스 추가를 사용
Cbitmap : 비트맵을 저장하는 객체 사용법1 : Brush에 맵핑 CBitmap bitmap; 리소스 아이디 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CBrush brush(&bitmap); dc.SelectObject(&brush); dc.Rectangle(0,0,200,200);
CBitmap 비트맵 정보 int CBitmap::GetBitmap (BITMAP* pBitMap) ; struct BITMAP { int bmType; int bmWidth; // 비트맵의 폭(픽셀 단위) int bmHeight; // 비트맵의 높이(픽셀 단위) int bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixel; LPVOID bmBits; };
CBitmap 비트맵 정보 출력 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); BITMAP bmpinfo; bitmap.GetBitmap(&bmpinfo); CString str.Format("가로 = %d, 세로 = %d\n", bmpinfo.bmWidth, bmpinfo.bmHeight); dc.TextOut(100,100,str);
비트맵을 직접 출력한다면… 한 점씩 그리지 않고 한꺼번에 메모리로 보낸다 (Block) (Transfer) 절차: 원래의 도화지가 있다 또 다른 도화지 준비 그 도화지에 그림 그리기 원래의 도화지로 그린거 오려붙이기
비트맵을 직접 출력한다면… 한 점씩 그리지 않고 한꺼번에 메모리로 보낸다 (Block) (Transfer) 절차: 원래의 도화지가 있다 CPaintDC dc; 또 다른 도화지 준비 CDC::CreateCompatibleDC(..); 그 도화지에 그림 그리기 CDC::SelectObject(…); 원래의 도화지로 그린거 오려붙이기 dc.BitBlt(…); Bit Block Transfer (BitBlt)
비트맵 출력 예제 CPaintDC dc(this); CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); BITMAP bmpInfo; bitmap.GetBitmap(&bmpInfo); CDC memDc; memDc.CreateCompatibleDC(&dc); memDc.SelectObject(&bitmap); dc.BitBlt(100, 100, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCCOPY);
CBitmap 비트맵 출력 함수 그림을 복사하는 방법 SRCCOPY, BOOL BitBlt (int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop) ; (스크린 디바이스 컨텍스트) pSrcDC (메모리 디바이스 컨텍스트) x y nWidth nHeight xSrc ySrc nWidth nHeight
CBitmap 비트맵 출력 함수 (cont'd) BOOL StretchBlt (int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop) ; pSrcDC (메모리 디바이스 컨텍스트) ySrc nSrcWidth xSrc nSrcHeight (스크린 디바이스 컨텍스트) y nWidth x nHeight
Memory에 그림그리고 넘겨주기 한꺼번에 절차: 1. 메모리DC 만들기 (CreateCompatibleDC) 2. 그림그릴 메모리 만들기 (CreateCompatibleBitmap) 3. DC와 Bitmap을 연결 (SelectObject) 4. 그림 그리기 5. 그려진 그림을 화면DC로 BitBlt 한꺼번에
Memory에 그림그리고 넘겨주기 한꺼번에 CPaintDC dc(this); CRect rect; GetClientRect(&rect); CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap bitmap; bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height()); memDC.SelectObject(&bitmap); memDC.Rectangle(0,0,100,100); dc.BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
Double Buffering using bitmap 그림이 빨리 그려진다. 그러나 여전히 깜박인다??? 화면을 매번 깨끗이 지우기 때문! “화면을 지울 필요가 있다”라는 메시지를 받아서 지우지 말자고 하자. WM_ERASEBKGND
숙제 #2 다다음주 화요일 (4월 1일) 마우스로 사각형 및 원을 그리는 프로그램을 완성 사각형(마우스 왼쪽 클릭), 원(마우스 오른 클릭) 그림 그려지는 순서 유지 Double Buffering 마우스 드래그를 이용 사각형(원) 생성시 크기 조절 Bells and Whistles: Extra Point 다각형 그리기 색을 선택