본문 바로가기

공부/MFC

Visual C++ 2008 MFC Chapter 7 GDI - 5 도형 그리기

프로젝트명은 TriangleDemo로 

옵션은 전과 같은 SDI



본 코드는 삼각형을 그려보는 코드이다

일단 무조건 코딩을 한다.
///////////////////////////////////////////////////
void CTriangleDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting

DWORD style[] = {6,3};
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(192,192,192);

CPen NewPen;
NewPen.CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT,20,&lb);
CPen* pOldPen = dc.SelectObject(&NewPen);

CBrush NewBrush(RGB(0,0,192));//청색 브러시를 선택하여 삼각형을 칠한다.
CBrush* pOldBrush =dc.SelectObject(&NewBrush);

dc.MoveTo(190,40);
dc.LineTo(290,190);
dc.LineTo(90,190);
dc.LineTo(190,40);
//두께가 20 픽셀인 선을 세번 그어 삼각형을 그린다.

dc.SelectObject(pOldBrush);
dc.SelectObject(pOldPen);
//기본값으로 재설정한다.

dc.MoveTo(190,40);
dc.LineTo(290,190);
dc.LineTo(90,190);
dc.LineTo(190,40);
//기본값으로 삼각형을 덧씌워 그린다.


}
/////////////////////////////////////////////////

 이 코드를 짜서 돌려보면

뭔가 이상한 점을 눈치 챌것이다.

분명 코드는 많은데 결국 작동하는 코드는 적다는 것.

출력화면을 보자.



분명 펜 뿐만 아니라 브러쉬 도 설정했지만

도형 내의 색이 칠해지지 않았고, 끝부분도 좀 매끄럽게 이어지는 느낌이 없다.

코드에 수정을 가해서 다음과 같이 다시 코딩을 하면.



void CTriangleDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting

DWORD style[] = {6,3};
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(192,192,192);

CPen NewPen;
NewPen.CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER,20,&lb); //PS_JOIN_MITER가 추가되었다.[추가코드]
CPen* pOldPen = dc.SelectObject(&NewPen);

CBrush NewBrush(RGB(0,0,192));//청색 브러시를 선택하여 삼각형을 칠한다.
CBrush* pOldBrush =dc.SelectObject(&NewBrush);

dc.BeginPath(); //경로 시작 [추가코드]
dc.MoveTo(190,40);
dc.LineTo(290,190);
dc.LineTo(90,190);
dc.LineTo(190,40); //두께가 20 픽셀인 선을 세번 그어 삼각형을 그린다.
dc.EndPath(); //경로 종료 [추가코드]
dc.StrokeAndFillPath(); //두 함수를 통하여 완성된 폐곡선을 통한 도형을 랜더링[추가코드]


dc.SelectObject(pOldBrush);
dc.SelectObject(pOldPen);
//기본값으로 재설정한다.

dc.MoveTo(190,40);
dc.LineTo(290,190);
dc.LineTo(90,190);
dc.LineTo(190,40);
//기본값으로 삼각형을 덧씌워 그린다.

}

///////////////////////////////
주석의 설명대로 
젤 위에 추가한 속성 코드는 연결부분의 처리에 관한 속성이고

그다음으로 dc.BeginPath(); 는 곡선간의 연결을 총해 dc.EndPath();와 합쳐져서 하나의 폐곡선을 만든다.

마지막으로  dc.StrokeAndFillPath(); 를 통해 랜더링을 해주면 브러쉬가 작동하게 된다.


////////////////////////////
출력화면은 이렇게 나온다.

 
/////////////////////


여기서 쓰인 선의 결합에 관한 스타일의 종류를 보자.






또다른 도형을 그리는 코딩 방법으로는 배열과 폴리곤 함수를 사용하는 것이다.

그럴 경우 위와 같은 긴 코딩이 필요 없이 간단하게 특정 도형을 그려낼 수 있다.[대신 선을 그려서 만드는 복잡한 도형은 안된다.]

/*
dc.BeginPath(); //경로 시작 [추가코드]
dc.MoveTo(190,40);
dc.LineTo(290,190);
dc.LineTo(90,190);
dc.LineTo(190,40); //두께가 20 픽셀인 선을 세번 그어 삼각형을 그린다.
dc.EndPath(); //경로 종료 [추가코드]
dc.StrokeAndFillPath(); //두 함수를 통하여 완성된 폐곡선을 통한 도형을 랜더링[추가코드]
*/

POINT arPt[3] ={{190,40}, {290,190}, {90,190}};
dc.Polygon(arPt,3);

/////////////////////////////////////////////

위의 것들을 모두 주석처리 해버리고 아래의 코드만으로도 삼각형이 그려진다.[채색도 되는건 당연하다.]


같은 방법으로 Rectangle() 함수와 Polygon() 함수로 사각형을 구현하면 다음과 같다.

/////////////////////////////////
void CTriangleDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting

DWORD style[] = {6,3};
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(192,192,192);

CPen NewPen;
NewPen.CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER,20,&lb); //PS_JOIN_MITER가 추가되었다.[추가코드]
CPen* pOldPen = dc.SelectObject(&NewPen);

CBrush NewBrush(RGB(0,0,192));//청색 브러시를 선택하여 삼각형을 칠한다.
CBrush* pOldBrush =dc.SelectObject(&NewBrush);


POINT arPt[4] = {{20,20} , {140,20}, {140, 140}, {20,140}}; //배열을 사용해서 4개의 점을 설정한다.
dc.Polygon(arPt,4); //폴리곤 함수를 사용해서 해당 배열을 연결하여 사각형을 그린다.

dc.Rectangle(CRect(180,20,300,140)); //함수를 사용해서 사각형을 그린다.



dc.SelectObject(pOldBrush);
dc.SelectObject(pOldPen); //기본값으로 재설정한다.

}

///////////////////
기존의 삼각형은 주석처리 하여 치워버렸다.

이렇게 하면 두께가 20인 픽셀인 선으로 둘러쌓인 [모서리는 각지게 속성이 정해진] 속이 색칠된 사각형이 두개 완성된다.

ㄴ출력화면

/////////////////////////////////////////////////////////////////////////////////

이번에는  사각형을 지우고[주석처리를 하든 지우든..] 원을 그려보자

코드는 다음과 같다.

void CTriangleDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting

CBrush NewBrush(RGB(0,192,192));
CBrush* pOldBrush = dc.SelectObject(&NewBrush); //브러시를 선택하여 도형을 칠한다.


dc.Rectangle(20,20,140,140); //사각형을 그리는 함수는
dc.Ellipse(20,20,140,140); //원을 그리는 함수와 사각형을 그리는 함수는 인자가 같다.

dc.SelectObject(*pOldBrush);//브러쉬 초기화

}

/////////////////////////////////

출력화면은 다음과 같다.
     


좌측은 코드 그대로 썼을 경우의 출력화면이고 우측은 원을 그리는 함수의 크기는 그대로 유지하고 위치만 우측으로 이동시킨 출력화면이다.[이해를 돕기 위해 일부러 나누어 보았다.]


이번에는 원이 아닌 부채꼴을 그리는 코드를 알아보자.


코드가 복잡해도 긁지 말고 직접 치는것이 이해에 도움이 된다. 사소한 것이지만 긁기보다는 직접 치도록 하자.


 void CTriangleDemoView::OnPaint()

{

CPaintDC dc(this); // device context for painting


CBrush NewBrush(RGB(0,192,192));

CBrush* pOldBrush = dc.SelectObject(&NewBrush); //브러시를 선택하여 도형을 칠한다.


CRect PieRect(20,20,140,140);

dc.Pie(PieRect, 

CPoint(PieRect.CenterPoint().x,PieRect.top),

CPoint(PieRect.right, PieRect.CenterPoint().y)); //내각이 270도인 부채꼴



PieRect = CRect(150,20,270,140);

dc.Pie(PieRect, 

CPoint(PieRect.right, PieRect.CenterPoint().y),

CPoint(PieRect.CenterPoint().x,PieRect.top)); //내각이 90도인 부채꼴

dc.SelectObject(pOldBrush);//브러쉬 초기화

}


////////////////////////////////////////////////////

출력화면은 다음과 같다.

 



이 코드에서 쓰이는 CDC 클래스의 함수인 Pie()함수는 두가지로 다중정의되어있고 MFC에서는 지금 사용한 것과 같은 형식을 가장 많이 사용한다.

이 함수는 4개의 좌표를 인자로 받기 때문에 복잡하며 각 인자를 따로 보면 이해가 쉽지 않다. 고 한다.

코드 내부에서 쓰인 함수 중 CenterPoint() 함수는 받은 값들의 중간값을 계산해내는 함수이다. 여기서는 계산 결과가 (20 + 140) / 2  인 80 의 값이 나온다. 

그러니까 어떤 방식이냐면

1. 원이 들어갈 사각형의 위치와 크기를 정한다.

2. 부채꼴이 시작될 위치와 끝날 위치를 정한다.

3. Pie함수에 사각형, 시작위치, 끝위치 를 인자로 집어넣는다.

라는 순서이다


이렇게 하면 될걸 뭘 그리 복잡하게 여러줄로 표현하는지 모르겠다.?

CPoint 속에 들어있는 인자 중 PieRect  구조체는 CRect 의 형식을 띄고 있다는 점에서 

숫자가 아니고 문자로 표현되어 아마 어렵게 느껴지는 것 일 지도 모르겠다.


//////////////////////////////////////////////////

마지막의 마지막으로 끝부분이 부채꼴 모양인 사각형을 그리는 함수에 대해 알아보자.

코드는 다음과 같다.

 void CTriangleDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting


DWORD style[] = {3,3}; //사용자 정의 스타일 배열 3,3
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(192,0,0);


CPen NewPen;
NewPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT |PS_JOIN_MITER, 3, &lb, 2, style);          //선 속성 설정, 굵기 3의 색은 빨간색인, 유저스타일 실선, 끝부분 처리는 뾰족함.
CPen* pOldPen = dc.SelectObject(&NewPen);


CBrush NewBrush(RGB(192,192,192));       //브러쉬 색 설정
CBrush* pOldBrush =dc.SelectObject(&NewBrush);

dc.RoundRect(CRect(20,20,140,140), CPoint(20,20));      //끝부분이 부채꼴인 사각형을 그리는 함수
        //사각형의 4개의 점과 내각이 90도인 부채꼴의 둥근 정도를 명시하는 좌표로 인자가 이루어져있다.
 
dc.SelectObject(pOldBrush); //브러시 초기화
dc.SelectObject(pOldPen); //펜 초기화

}

/////////////////////////////

출력화면

 

 이번 글에 사용된 코드 파일.

[맨 마지막의 코드만 활성화 되어있고 나머지 코드들은 모두 주석처리 되어있으니 임의로 주석을 설정/해제 하면서 보면 되지만 왠간하면 직접 치면서 따라하는걸 추천함.]


 

GDI는 정말 양이 많다. 으으.