프로그래밍 모델의 변경 내용

다음 섹션에서는 Windows GDI+를 사용한 프로그래밍이 Windows GDI(그래픽 디바이스 인터페이스)를 사용한 프로그래밍과 다른 여러 가지 방법을 설명합니다.

디바이스 컨텍스트, 핸들 및 그래픽 개체

GDI(이전 버전의 Windows에 포함된 그래픽 디바이스 인터페이스)를 사용하여 프로그램을 작성한 경우 DC(디바이스 컨텍스트)에 대해 잘 알고 있습니다. 디바이스 컨텍스트는 Windows에서 특정 디스플레이 디바이스의 기능에 대한 정보와 해당 디바이스에서 항목을 그리는 방법을 지정하는 특성을 저장하는 데 사용하는 구조입니다. 비디오 디스플레이에 대한 디바이스 컨텍스트는 디스플레이의 특정 창과도 연결됩니다. 먼저 HDC(디바이스 컨텍스트)에 대한 핸들을 가져온 다음 실제로 그리기를 수행하는 GDI 함수에 인수로 해당 핸들을 전달합니다. 또한 디바이스 컨텍스트의 특성을 가져오거나 설정하는 GDI 함수에 인수로 핸들을 전달합니다.

GDI+를 사용하는 경우 GDI를 사용할 때처럼 핸들 및 디바이스 컨텍스트에 관심을 가질 필요가 없습니다. Graphics 개체를 만든 다음 익숙한 개체 지향 스타일인 myGraphicsObject.DrawLine(parameters)에서 해당 메서드를 호출하기만 하면 됩니다. Graphics 개체는 디바이스 컨텍스트가 GDI의 핵심인 것처럼 GDI+의 핵심입니다. 디바이스 컨텍스트와 Graphics 개체는 비슷한 역할을 하지만 GDI(디바이스 컨텍스트)와 함께 사용되는 핸들 기반 프로그래밍 모델과 그래픽 개체(GDI+)에 사용되는 개체 지향 모델 간에는 몇 가지 근본적인 차이점이 있습니다.

디바이스 컨텍스트와 같은 Graphics 개체는 화면의 특정 창과 연결되며 항목을 그리는 방법을 지정하는 특성(예: 다듬기 모드 및 텍스트 렌더링 힌트)을 포함합니다. 그러나 Graphics 개체는 디바이스 컨텍스트와 같이 펜, 브러시, 경로, 이미지 또는 글꼴에 연결되지 않습니다. 예를 들어 GDI에서 디바이스 컨텍스트를 사용하여 선을 그리려면 먼저 SelectObject 를 호출하여 펜 개체를 디바이스 컨텍스트와 연결해야 합니다. 이를 디바이스 컨텍스트로 펜 선택이라고 합니다. 디바이스 컨텍스트에 그려진 모든 줄은 다른 펜을 선택할 때까지 해당 펜을 사용합니다. GDI+를 사용하면 Graphics 클래스의 DrawLine 메서드에 펜 개체를 인수로 전달 합니다 . 지정된 Pen 개체를 Graphics 개체와 연결하지 않고도 각 일련의 DrawLine 호출에서 다른 Pen 개체를 사용할 수 있습니다.

선을 그리는 두 가지 방법

다음 두 예제에서는 각각 위치(20, 10)에서 위치(200,100)로 너비 3의 빨간색 선을 그립니다. 첫 번째 예제에서는 GDI를 호출하고 두 번째 예제는 C++ 클래스 인터페이스를 통해 GDI+를 호출합니다.

GDI를 사용하여 선 그리기

GDI를 사용하여 선을 그리려면 디바이스 컨텍스트와 펜의 두 개체가 필요합니다. BeginPaint를 호출하여 디바이스 컨텍스트에 대한 핸들과 CreatePen을 호출하여 펜에 대한 핸들을 가져옵니다. 다음으로 SelectObject 를 호출하여 디바이스 컨텍스트로 펜을 선택합니다. MoveToEx를 호출하여 펜 위치를 (20, 10)로 설정한 다음 LineTo를 호출하여 해당 펜 위치에서 (200, 100)로 선을 그립니다. MoveToEx와 LineTo 는 모두 hdc 를 인수로 받습니다.

HDC          hdc;
PAINTSTRUCT  ps;
HPEN         hPen;
HPEN         hPenOld;
hdc = BeginPaint(hWnd, &ps);
   hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
   hPenOld = (HPEN)SelectObject(hdc, hPen);
   MoveToEx(hdc, 20, 10, NULL);
   LineTo(hdc, 200, 100);
   SelectObject(hdc, hPenOld);
   DeleteObject(hPen);
EndPaint(hWnd, &ps);

GDI+ 및 C++ 클래스 인터페이스를 사용하여 선 그리기

GDI+ 및 C++ 클래스 인터페이스를 사용하여 선을 그리려면 Graphics 개체와 Pen 개체가 필요합니다. 이러한 개체에 대한 핸들은 Windows에 요청하지 않습니다. 대신 생성자를 사용하여 Graphics 클래스(Graphics 개체)의 instance 클래스(Pen 개체)의 instance 만듭니다. 선을 그리려면 Graphics 클래스의 Graphics::D rawLine 메서드를 호출합니다. Graphics::D rawLine 메서드의 첫 번째 매개 변수는 개체에 대한 포인터입니다. 이는 이전 GDI 예제와 같이 디바이스 컨텍스트로 펜을 선택하는 것보다 더 간단하고 유연한 구성표입니다.

HDC          hdc;
PAINTSTRUCT  ps;
Pen*         myPen;
Graphics*    myGraphics;
hdc = BeginPaint(hWnd, &ps);
   myPen = new Pen(Color(255, 255, 0, 0), 3);
   myGraphics = new Graphics(hdc);
   myGraphics->DrawLine(myPen, 20, 10, 200, 100);
   delete myGraphics;
   delete myPen;
EndPaint(hWnd, &ps);

펜, 브러시, 경로, 이미지 및 글꼴을 매개 변수로

앞의 예제에서는 그리기 메서드를 제공하는 Graphics 개체와 별도로 개체를 만들고 유지 관리할 수 있음을 보여 줍니다. Brush, GraphicsPath, ImageFont 개체를 Graphics 개체와 별도로 만들고 유지 관리할 수도 있습니다. Graphics 클래스에서 제공하는 대부분의 그리기 메서드는 Brush, GraphicsPath, Image 또는 Font 개체를 인수로 받습니다. 예를 들어 Brush 개체의 주소는 FillRectangle 메서드에 인수로 전달되고 GraphicsPath 개체의 주소는 Graphics::D rawPath 메서드에 인수로 전달됩니다. 마찬가지로 ImageFont 개체의 주소는 DrawImageDrawString 메서드에 전달됩니다. 이는 디바이스 컨텍스트에 브러시, 경로, 이미지 또는 글꼴을 선택한 다음 그리기 함수에 인수로 디바이스 컨텍스트에 핸들을 전달하는 GDI와는 대조적입니다.

메서드 오버로드

많은 GDI+ 메서드가 오버로드됩니다. 즉, 여러 메서드가 동일한 이름을 공유하지만 매개 변수 목록이 다릅니다. 예를 들어 Graphics 클래스의 DrawLine 메서드는 다음 형식으로 제공됩니다.

Status DrawLine(IN const Pen* pen,
                IN REAL x1,
                IN REAL y1,
                IN REAL x2,
                IN REAL y2);
Status DrawLine(IN const Pen* pen,
                IN const PointF& pt1,
                IN const PointF& pt2);
Status DrawLine(IN const Pen* pen,
                IN INT x1,
                IN INT y1,
                IN INT x2,
                IN INT y2);
    
Status DrawLine(IN const Pen* pen,
                IN const Point& pt1,
                IN const Point& pt2);

위의 4가지 DrawLine 변형은 모두 개체, 시작점의 좌표 및 끝점의 좌표에 대한 포인터를 받습니다. 처음 두 변형은 좌표를 부동 소수점 숫자로 받고 마지막 두 변형은 좌표를 정수로 받습니다. 첫 번째 및 세 번째 변형은 좌표를 4개의 개별 숫자 목록으로 수신하고 두 번째 및 네 번째 변형은 좌표를 Point(또는 PointF) 개체 쌍으로 받습니다.

더 이상 현재 위치 없음

이전에 표시된 DrawLine 메서드에서 줄의 시작점과 끝점이 모두 인수로 수신됩니다. 이는 MoveToEx를 호출하여 현재 펜 위치와 LineTo를 차례로 설정하여 (x1, y1)에서 시작하여 (x2, y2)로 끝나는 선을 그리는 GDI 스키마에서 벗어난 것입니다. GDI+는 전체적으로 현재 위치의 개념을 포기했습니다.

그리기 및 채우기에 대한 별도의 메서드

GDI+는 윤곽선을 그리고 사각형과 같은 셰이프의 내부를 채우는 데 있어 GDI보다 더 유연합니다. GDI에는 윤곽선을 그리고 사각형의 내부를 한 단계로 채우는 Rectangle 함수가 있습니다. 윤곽선은 현재 선택한 펜으로 그려지고 내부는 현재 선택된 브러시로 채워집니다.

hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);
Rectangle(hdc, 100, 50, 200, 80);

GDI+에는 윤곽선을 그리고 사각형의 내부를 채우는 별도의 메서드가 있습니다. Graphics 클래스의 DrawRectangle 메서드는 Pen 개체의 주소를 해당 매개 변수 중 하나로 사용하고 FillRectangle 메서드는 Brush 개체의 주소를 해당 매개 변수 중 하나로 사용합니다.

HatchBrush* myHatchBrush = new HatchBrush(
   HatchStyleCross,
   Color(255, 0, 255, 0),
   Color(255, 0, 0, 255));
Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);
myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);

GDI+의 FillRectangleDrawRectangle 메서드는 사각형의 왼쪽 가장자리, 위쪽, 너비 및 높이를 지정하는 인수를 받습니다. 이는 사각형의 왼쪽 가장자리, 오른쪽 가장자리, 위쪽 및 아래쪽을 지정하는 인수를 사용하는 GDI사각형 함수와는 대조적입니다. 또한 GDI+의 Color 클래스 생성자에는 4개의 매개 변수가 있습니다. 마지막 세 매개 변수는 일반적인 빨간색, 녹색 및 파란색 값입니다. 첫 번째 매개 변수는 그리는 색이 배경색과 혼합되는 정도를 지정하는 알파 값입니다.

지역 생성

GDI는 지역을 만들기 위한 여러 함수를 제공합니다. CreateRectRgn, CreateEllpticRgn, CreateRoundRectRgn, CreatePolygonRgn 및 CreatePolyPolygonRgn. GDI+의 Region 클래스에는 사각형, 타원, 둥근 사각형 및 다각형을 인수로 사용하는 유사한 생성자가 있을 수 있지만 그렇지 않습니다. GDI+의 Region 클래스는 Rect 개체 참조를 수신하는 생성자와 GraphicsPath 개체의 주소를 받는 다른 생성자를 제공합니다. 타원, 둥근 사각형 또는 다각형을 기반으로 지역을 구성하려는 경우 GraphicsPath 개체(예: 타원 포함)를 만든 다음 해당 GraphicsPath 개체의 주소를 Region 생성자에 전달하여 쉽게 만들 수 있습니다.

GDI+를 사용하면 셰이프와 경로를 결합하여 복잡한 영역을 쉽게 형성할 수 있습니다. Region 클래스에는 경로 또는 다른 지역으로 기존 지역을 보강하는 데 사용할 수 있는 UnionIntersect 메서드가 있습니다. GDI+ 스키마의 한 가지 좋은 기능은 GraphicsPath 개체가 Region 생성자에 인수로 전달될 때 제거되지 않는다는 것입니다. GDI에서 PathToRegion 함수를 사용하여 경로를 영역으로 변환할 수 있지만 프로세스에서 경로가 제거됩니다. 또한 GraphicsPath 개체는 주소가 Union 또는 Intersect 메서드에 인수로 전달될 때 제거되지 않으므로 지정된 경로를 여러 개별 지역의 구성 요소로 사용할 수 있습니다. 다음 예제에서 이를 확인할 수 있습니다. onePath가 이미 초기화된 GraphicsPath 개체(단순 또는 복합)에 대한 포인터라고 가정합니다.

Region  region1(rect1);
Region  region2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);