제 6 장그래픽객체의사용 6.1 GDI와 DC의개념 6.2 GDI 객체실습 6-1 직선과도형및비트맵그리기 6.3 GDI+ 의개념실습 6-2 사각형뷰포트에원그리기
GDI 의개념 Graphic Device Interface 윈도우가하드웨어를제어할수있도록응용프로그램에제공하는모든기능 응용프로그램과디바이스드라이버의중간역할 응용프로그램에대한장치독립적인그래픽동작수행
Device Context(DC) 의개념 일종의핸들 애플리케이션과출력장치를연결하는역할 애플리케이션이출력에대한허가를얻고, 또한그려지는영역을결정하는역할 GDI 에의해내부적으로유지되는데이터구조 여러가지그래픽속성에대한값을가짐 Ex) 텍스트속성 / 색상, 매핑모드, 글꼴 DC 를사용하는이유 독립적인하드웨어출력을할수있어출력장치에상관없이동일한방법으로출력을설정 DC 를얻고나면, 반드시작업완료시해제한다
DC 를얻는방법 4 가지 DC 를얻는방법 1 OnDraw() 함수, OnPaint() 함수를이용 2 GetDC() 함수를이용 3 CClientDC 클래스를이용 4 CWindowDC 클래스를이용
OnDraw() 함수, OnPaint() 함수를이용 OnDraw() 함수의인자 - CDC 오브젝트 Void CPractice6_1View:: OnDraw(CDC * pdc) { } OnPaint() 함수내의 CPaintDC 오브젝트 Void CPractice6_1View::OnPaint() { CPaintDC dc(this) } 윈도우나클라이언트영역이다시그려져야할경우수행 DC 의해제는 MFC 내부코드에존재한다.
GetDC() 함수를이용 이함수의포인터반환값을받아서사용 ReleaseDC() 함수를호출하여반드시해제 사용예 CDC *pdc = GetDC(); ReleaseDC(pDC); 이방법으로 DC 를얻는것은일시적인것으로윈도우의크기가변하면출력한내용이사라진다.
CClientDC 클래스를이용 CClientDC 는 CDC 클래스의파생클래스 Device Context 의생성 / 해제자동적수행 생성자함수에서 GetDC() 함수를호출 소멸자함수에서 ReleaseDC() 함수를호출 윈도우에대한핸들값이필요 일시적으로윈도우의클라이언트영역에서그래픽개체를사용할경우에이용 사용예 CClientDC dc(this)
CWindowDC 클래스를이용 윈도우 ( 프레임 ) 영역에그래픽요소를출력하고자할때사용한다. GetWindowDC() 함수를이용하여 CWindowDC 클래스의인스턴스를포인터형태로넘겨받아이용 작업수행후, ReleaseDC() 함수로해제 사용예 CWindowDC *pdc = GetWindowDC(); ReleaseDC();
GDI 객체 GDI 기본구성요소 선과곡선 (Lines and Curves) 직선, 사각형, 타원, 호, 베지어곡선 채워진영역 (Filled Areas) 브러시개체를이용 색상, 패턴, 비트맵이미지 비트맵 (Bitmaps) 디스플레이장치의픽셀과일치하는직사각형배열 래스터그래픽의기본적인도구 텍스트 (Text)
화면에그래픽출력하기위한요소 GDI 객체 GDI 객체클래스기본값사용용도 펜 CPen 검정색, 실선, 1 픽셀크기 점, 선, 테두리 브러시 CBrush 무늬없는흰색내부 ( 영역 ) 채우기 폰트 CFont 시스템폰트문자의폰트 비트맵 CBitmap 없음비트맵출력 영역 CRgn 없음 영역만들기, 변경하기 팔레트 CPalette 없음팔레트조작
객체를사용하는방법 1 GDI 객체를생성 객체클래스의 Create 계열함수이용 2 객체를 DC 에등록 SelectObject() 함수를이용 기존설정된객체는포인터로저장 3 DC 를사용하여그래픽출력 4 이전객체로환원 5 객체를삭제 DeleteObject() 함수이용
펜 (Pen) 펜 (Pen) 선이나영역의경계선을그릴때사용 선의두께, 선이색상, 선의스타일을설정 펜을사용하는방법 1 CPen pen *oldpen pen.createpen(ps_solid, 1,RGB(0,0,0)); 2 oldpen = pdc->selectobject(&pen); 3 pdc->ellipse(0,0,10,10); 4 pdc->selectobject(oldpen); 5 pen.deleteobject();
CreatePen() 함수 CreatePen() 함수는 Pen 을생성하는함수로원형은다음과같다. BOOL CreatePen(int npenstyle, int nwidth, COLORREF crcolor); npenstyle : 펜의스타일 nwidth : 펜의굵기 crcolor : 펜의색상
펜의스타일 펜의스타일내용모양 PS_SOLID PS_DASH PS_DOT PS_DASHDOT 실선파선점선일점쇄선 PS_DASHDOTDOT 이점쇄선 PS_NULL 선을그리지않음
브러시 (Brush) 브러시 (Brush) 영역의내부를채울때사용 채울색, 패턴등이사용 브러시를사용하는방법 1 CBrush brush *oldbrush brush.createsolidbrush(rgb(0,0,0)); bush.createhatchbrush(hs_cross,rgb(0,0,0)); 2 oldbrush = pdc->selectobject(&brush); 3 pdc->ellipse(0,0,10,10); 4 pdc->selectobject(oldbrush); 5 brush.deleteobject();
브러시 (Brush) CreateSolidBrush() 함수 단일색으로칠하는브러시를생성하는함수 CreateHatchBrush() 함수 일정한패턴을가진해치브러시를생성하는함수. 해치브러쉬의스타일 해치브러시의스타일내용모양 HS_BDIAGONAL HS_CROSS HS_DIAGCROSS HS_FDIAGONAL HS_HORIZONTAL HS_VERTICAL 오른쪽에서왼쪽으로 45도내려가는빗금십자가형태의빗금 X자형태의빗금왼쪽에서오른쪽으로 45도내려가는빗금수평으로빗금수직으로빗금
그래픽함수 선그리기 MoveTo(int x, int y) 함수 LineTo(int x, int y) 함수 사각형그리기 Rectangle(int x1, int y1, int x2, int y2) 원그리기 Ellipse(int x1, int y1, int x2, int y2) 다각형그리기 Polyline(LPPOINT lppoints, int ncount) Polygon(LPPOINT lppoints, int ncount) 베지어곡선그리기 PolyBezier(const POINT* lppoints, int ncount)
래스터오퍼레이션 래스터오퍼레이션 새로그려야할그림과기존의화면에그려져있는그림을합성하는것 펜과브러시에적용되며 SetROP2() 함수로설정한다. R2_COPYPEN : 배경그림무시하고새로그려지는그림을출력 R2_XORPEN : 한번그리면그림이그려지고다시한번그리면원래의바탕색이복원
GDI 객체 비트맵 CBitmap 클래스를이용하는객체로비트맵을생성하거나읽어서비트맵을출력할때사용 비트맵의래스터오퍼레이션 SRCCOPY : 배경그림무시하고비트맵출력 SRCAND : 배경그림과 AND 연산 SRCPAINT : 배경그림과 OR 연산
비트맵을사용하는방법 1 화면 DC 와메모리 DC 를생성 CClinetDC dc(this); CDC memdc; 2 화면 DC 와호환성을갖는 DC 를만든다. memdc.createcompatibledc(&dc); 3 비트맵을읽어온다 CBitmap bitmap, *oldbitmap; bitmap.loadbitmap(idb_bitmap1); 4 메모리 DC 에비트맵을설정한다. oldbitmap = memdc.selectobject(&bitmap); 5 비트맵블록을전송한다. dc.bitblt(0, 0, 450, 85, &memdc, 0, 0, SRCCOPY); 6 DC 를복원한다. memdc.selectobject(oldbitmap);
폰트 (font) CFont 클래스를이용하는객체로문자를출력할때사용하며글자의모양, 크기가설정 폰트의종류 논리적인폰트 : 이상적인폰트에대한표현으로실제로존재하는것이아니라유사한폰트를얻기위해사용 물리적인폰트 : 실제로시스템에설치되어있는폰트를의미하며실제로화면에나타난다.
폰트를사용하는방법 폰트를출력하기위해서는원하는폰트에대해논리적인폰트를 LOGFONT 타입으로기술하여생성하고 DC 에폰트를선택하여넣는다. 윈도우 GDI 의폰트맵퍼가시스템에설치되어있는폰트들중에가장가까운물리적인폰트를찾아출력한다.
실습 6-1 직선과도형및비트맵그리기 직선, 원, 다각형, 비트맵을그리는프로그램을작성 러버밴드 (Rubber Band) 를이용하여마우스움직임을따라다니면서그림을그릴것이다. 러버밴드를이용한직선, 원, 다각형을그려볼것이다. DC 를얻는방법, GDI 객체의사용법과그래픽함수를사용하는내용
러버밴드기법 그리기작업을하다보면마우스의움직임에따라가상의선이늘었다줄었다하는것을볼수있는데이러한것을러버밴드 (Rubber Band) 라고부른다. 러버밴드로그림을그리려면 R2_NOTXORPEN 래스터오퍼레이션을사용하여그림을그린다. 구현방법 이전에그려진그림을지움 새로운그림을그림 마우스가움직였을때이전에그려진그림이지워질수있도록현재점저장
실습 6-1 프로그램작성순서 1) 실습 5-3 프로젝트를연다 2) 필요한멤버변수를추가한다. 직선, 원, 다각형을그리기위한변수 3) 왼쪽마우스를눌렸을때의동작을지정한다. 직선, 원그리기 : 시작점과이전점에현재점을저장하고왼쪽버튼이눌린것을체크하고, 처음그리는것으로체크한다 다각형그리기 : 처음그리는것이면시작점과이전점에현재점을저장하고, 처음그리지않는것으로체크한다음배열에현재점을저장하고카운트를증가한다. 다각형을처음그리는것이아니면시작점과이전점에현재점을저장하고, 배열에현재점을저장하고카운트를증가한다.
실습 6-1 프로그램작성순서 4) 마우스가움직일때의동작을지정한다. 먼저펜과브러시를생성하고그리기모드에따라러버밴드로직선, 원, 다각형을그린다. 5) 왼쪽마우스를놓았을때의동작을지정한다. 그리기모드가직선, 원그리기이면다시직선, 원을그리기위해체크변수를초기화한다. Invalidate() 함수를이용하여 OnDraw() 함수를호출한다.
실습 6-1 프로그램작성순서 6) 오른쪽마우스를눌렸을때동작을지정한다. 그리기모드가다각형그리기이면배열에현재점을저장하고카운트를증가한다. 다시다각형을그리기위해체크변수를초기화하고, Invalidate() 함수를이용하여 OnDraw() 함수를호출한다. 그런다음마우스캡쳐를해제하고이동범위제한을해제한다. 7) OnDraw() 함수에마지막으로그리는루틴을추가한다.
실습 6-1 프로그램작성순서 8) 문맥메뉴가제대로작동하도록수정한다. 다각형그리기모드일때다각형을완성하기위해오른쪽마우스를사용한다. 다각형그리기모드에서다각형을완성하기위해오른쪽마우스를클릭할경우에는문맥메뉴가팝업되지않도록수정한다. 9) 선과면의색상을변경한다. 선의색상을변경하는것은펜의색상을변경한다 면의색상을변경하는것은브러시의색상을변경하면된다. 10) 면의무늬를변경한다.
실습 6-1 프로그램작성순서 11) 리소스에비트맵을등록한다. 리소스로부터비트맵을읽어와화면에출력하려면리소스에비트맵이등록되어있어야한다. 12)OnDraw() 함수에비트맵을출력할코드를입력한다. 먼저호환성있는메모리 DC 를생성하고리소스에서비트맵을읽어메모리 DC 에비트맵을설정한다음비트맵출력모드에따라비트맵을출력한다. 13) 프로그램을실행시켜본다.
직선, 원그릴때마우스메시지에대한기능 1 왼쪽마우스버튼누름 : 시작점과이전점에현재점을저장한다 2 왼쪽마우스버튼누른채로마우스움직일때 : 러버밴드로직선, 원, 사각형을그린다. (R2_NOTXORPEN 이용 ) 3 왼쪽마우스버튼을놓음 : OnDraw() 함수를호출하여마지막직선, 원, 사각형을그린다. (R2_COPYPEN 이용 )
다각형그릴때마우스메시지에대한기능 1 왼쪽마우스버튼누름 ( 처음 ) : 시작점과이전점에현재점을저장하고배열에현재점을저장한다. 2 마우스움직일때 : 러버밴드로직선을그린다. (R2_NOTXORPEN 이용 ) 3 왼쪽마우스버튼누름 ( 반복 ) : 시작점과이전점에현재점을저장하고배열에현재점을저장한다. ( 반복 ) 4 마우스움직일때 ( 반복 ) : 러버밴드로직선을그린다. (R2_NOTXORPEN 이용 ) 5 오른쪽마우스버튼을누름 : 배열에현재점을저장하고 OnDraw() 함수를호출하여배열에저장된순서대로마지막다각형을그린다. (R2_COPYPEN 이용 )
실습 6-1 실행화면
실습 6-1 실행화면
GDI+ 의개념 GDI+ GDI 모듈의업그레이드버전 복잡하고섬세한그래픽을출력할수있는모듈 GID 와 GDI+ 의차이점
GDI 와 GDI+ 의차이점 GDI+ 는 Graphics 객체를먼저생성해야한다. 그리기함수들은 Graphics 클래스의멤버함수 출력함수들은그리기에필요한값을인수로전달받는다. 똑같은도형을그리는함수도인수의타입에따라여러가지로나뉜다. GDI+ 오브젝트들은 C++ 객체이므로메모리해제하는코드를따로작성할필요가없다. 소멸자함수에서메모리를해제해준다 GDI+ 에서사용하는문자열은유니코드시스템을사용해야한다. GDI+ 에서는다양한그래픽파일포맷을지원한다.
GDI+ 클래스계층
GDI+ 클래스 Graphics 클래스 GDI+ 의가장중요하고기본이되는클래스 출력을하려면이클래스의객체를먼저생성해야한다. 다양한생성자함수 Graphics(HDC hdc) Graphics(HDC hdc, HANDLE hdevice) Graphics(HWND hwnd, BOOL im) Graphics(Image* image)
GDI+ 클래스 Pen 클래스 선을그릴때사용하는그래픽오브젝트 생성자함수 Pen(const Color &color, REAL width) Pen(const Brush *brush, REAL width) SetDashStyle( ) 함수 선의모양을변경하는함수 함수원형 SetDashStyle(DashStyle dashstyle)
GDI+ 클래스 SetDashStyle 펜의스타일 펜의스타일내용모양 DashStyleSolid DashStyleDash DashStyleDot DashStyleDashDot DashStyleDashDotDot DashStyleCustom 실선파선점선일점쇄선이점쇄선선을그리지않음
GDI+ 클래스 Brush 클래스 채색하는무늬를만드는방법에따라여러종류의클래스계층을구성
GDI+ 클래스 Brush 클래스 ( 계속 ) LinearGradientBrush 클래스 지정한두색상이점점변하는모양으로채색하는브러시 6 가지생성자함수가있음 LinearGradientBrush(const Point &point1, const Point &point2, const Color &color1, const Color &color2)
GDI+ 클래스 Brush 클래스 ( 계속 ) SolidBrush 클래스 단색브러시로가장기본적인브러시 생성자함수 SolidBrush(const Color &color) HatchBrush 클래스 무늬가있는브러시 52 가지의무늬를제공 (GDI 는 6 가지무늬제공 ) 생성자함수 HatchBrush(HatchStyle hatchstyle, const Color &forecolor, const Color &backcolor)
GDI+ 그래픽함수 선그리기 DrawLine(const Pen *pen, const Point &pt1, const Point &pt2) DrawLine(const Pen *pen, INT x1, INT y1, INT x2, INT y2) DrawLine(const Pen *pen, const PointF &pt1, const PointF &pt2) DrawLine(const Pen *pen, REAL x1, REAL y1, REAL x2, REAL y2)
GDI+ 그래픽함수 사각형그리기 GDI 는 LTRB 방식을사용하고 GDI+ 는 XYWH( 좌상단점좌표와사각형의폭과높이 ) 방식을사용한다. DrawRectangle(const Pen *pen, const Rect &rect) DrawRectangle(const Pen *pen, INT x, INT y, INT width, INT height)
GDI+ 그래픽함수 원그리기 주어진사각형에내접하는타원을그린다. Status DrawEllipse(const Pen *pen, const Rect &rect) StatusDrawEllipse (const Pen *pen, INT x, INT y, INT width, INT height) 다각형그리기 Status DrawPolygon(const Pen *pen, const Point *points, INT count)
GDI+ 그래픽함수 곡선그리기 카디날곡선과베지어곡선을지원 카디날곡선 Status DrawCurve(const Pen *pen, cont Point *points, INT count, REAL tension) 베지어곡선 Status DrawBezier(const Pen *pen, Point& pt1, Point& pt2, Point& pt3, Point& pt4)
GDI+ 클래스 Font 클래스 Font 클래스로객체를생성한후 DrawString() 함수로이객체의포인터를전달하면문자열출력에폰트가사용된다. 생성자함수 Font(const WCHAR *familyname, REAL emsize, INT sytle, Unit unit, const FontCollection *fontcollection)
폰트관련그래픽함수 문자열출력함수 Status DrawString(const WCHAR *string, INT length, cont Font *font, const PointF &origin, const Brush *brush) Status DrawString(const WCHAR *string, INT length, const Font *font, const PointF &origin, const StringFormat *stringformat, const Brush *brush); Status DrawString(const WCHAR *string, INT length, const Font *font, const RectF &layoutrect, const StringFormat *stringformat, const Brush *brush);
실습 6-2 사각형영역을만든후그안에원그리기 이프로젝트는우선사각형을그리면그사각형이 viewport 가된다. 그리고원을그리게되면 viewport 밖으로나간부분의원은그려지지않게한다. 또한원의해상도를증가하고감소할수있는기능이있게구현한다. 이런기능을갖기위해서는원을그릴때 Ellipse() 함수를사용하여서는안된다.
실습 6-2 실행화면
실습 6-2 프로그램작성순서 1) 단일문서 기반의프로젝트를생성한다. 2) GDI+ 라이브러리를초기화한다. 3) 메뉴리소스를편집한다. 4) 툴바리소스를편집한다. 5) 상태표시줄에팬을만들고문자열을출력 6) 메뉴를동작하게한다. 7) 문맥메뉴를만든다.
실습 6-2 프로그램작성순서 8) 도형을그리기위한변수를추가한다 사각형, 원을그리기위한변수 9) WM_LBUTTONDOWN 에대한메시지핸들러함수를만든다. 10) 마우스이동에대한메시지핸들러함수를만든다. 11) WM_LBUTTONUP 에대한메시지핸들러함수를만든다. 12) 원을구하는함수를만든다.
실습 6-2 프로그램작성순서 13) OnDraw() 함수에마지막으로그리는루틴을추가한다. 14) 원의해상도를조절할수있게한다. 15) 프로그램을실행시킨다.
연습문제 6-1. 펜과지우개를구현하여그림을그리고지우는프로그램을구현한다. 왼쪽마우스는펜의기능을가지며왼쪽마우스를누르고이동시키면이동시키는대로내용이출력된다. 대화상자를통해크기와색상을변경할수있다. 오른쪽마우스는지우개기능을가지며대화상자를통해펜의크기를조절할수있다. 오른쪽마우스를누르고이동시키면이동시키는대로출력된내용이지워진다. 크기와색상을조절하는대화상자는툴바를통해출력된다.
연습문제 6-1 툴바구성 [ 새파일 ] [ 펜의크기 ] [ 펜의색상 ] [ 지우개 ] 펜과지우게설정대화상자
연습문제 6-1 실행화면 [ 처음실행화면 ] [ 그리기화면 ] [ 펜크기설정대화상자 ] [ 지우개크기설정대화상자 ]
연습문제 6-2. 도킹팬윈도우를이용하여문자열을출력하는프로그램을작성하라. 도킹팬윈도우를이용하여위치와문자열을입력받아그문자열을출력한다. 색상과폰트공용대화상자를이용하여색상과글꼴및크기를변경할수있어야하며출력된문자열을키보드의방향키로이동시킬수있어야한다.
연습문제 6-2 실행화면 문자열출력 문자열폰트및색상변경