컨트롤 페인팅 및 그리기(Windows Forms .NET)

사용자 지정 컨트롤 그리기는 Windows Forms에서 간소화된 여러 가지 복잡한 작업 중 하나입니다. 사용자 지정 컨트롤을 작성할 때 다양한 옵션을 사용하여 컨트롤의 그래픽 모양을 처리할 수 있습니다. Control에서 상속되는 컨트롤인 사용자 지정 컨트롤을 작성하는 경우 그래픽 표현을 렌더링하는 코드를 제공해야 합니다.

중요

.NET 7 및 .NET 6에 관한 데스크톱 가이드 설명서는 제작 중입니다.

UserControl 또는 기존 Windows Forms 컨트롤 중 하나에서 상속되는 컨트롤인 복합 컨트롤을 만드는 경우 표준 그래픽 표현을 재정의하고 사용자 고유의 그래픽 코드를 제공할 수 있습니다.

새 컨트롤을 만들지 않고 기존 컨트롤의 사용자 지정 렌더링을 제공하려는 경우에는 옵션이 더 제한됩니다. 하지만 여전히 컨트롤과 애플리케이션의 그래픽을 다양하게 변형할 수 있습니다.

컨트롤 렌더링에는 다음과 같은 요소가 사용됩니다.

  • 기본 클래스 System.Windows.Forms.Control에서 제공하는 그리기 기능
  • GDI 그래픽 라이브러리의 필수 요소
  • 그리기 영역의 기하 도형
  • 그래픽 리소스 해제 절차

컨트롤에서 제공하는 그리기

기본 클래스 Control은 해당 Paint 이벤트를 통해 그리기 기능을 제공합니다. 컨트롤은 표시를 업데이트해야 할 때마다 Paint 이벤트를 발생시킵니다. .NET의 이벤트에 대한 자세한 내용은 이벤트 처리 및 발생을 참조하세요.

Paint 이벤트의 이벤트 데이터 클래스인 PaintEventArgs는 컨트롤을 그리는 데 필요한 데이터(그래픽 개체 핸들 및 그릴 영역을 나타내는 사각형)를 저장합니다.

public class PaintEventArgs : EventArgs, IDisposable
{

    public System.Drawing.Rectangle ClipRectangle {get;}
    public System.Drawing.Graphics Graphics {get;}

    // Other properties and methods.
}
Public Class PaintEventArgs
    Inherits EventArgs
    Implements IDisposable

    Public ReadOnly Property ClipRectangle As System.Drawing.Rectangle
    Public ReadOnly Property Graphics As System.Drawing.Graphics

    ' Other properties and methods.
End Class

Graphics는 이 문서의 뒷부분에 있는 GDI 부분에 설명된 대로 그리기 기능을 캡슐화하는 관리형 클래스입니다. ClipRectangleRectangle 구조 인스턴스로, 컨트롤이 그릴 수 있는 사용 가능한 영역을 정의합니다. 컨트롤 개발자는 이 문서의 뒷부분에 있는 기하 도형 부분에 설명된 대로 컨트롤의 ClipRectangle 속성을 사용하여 ClipRectangle을 컴퓨팅할 수 있습니다.

OnPaint

컨트롤은 Control에서 상속받은 OnPaint 메서드를 재정의하여 렌더링 논리를 제공해야 합니다. OnPaint는 전달된 PaintEventArgs 인스턴스의 GraphicsClipRectangle 속성을 통해 그릴 사각형과 그래픽 개체에 액세스합니다.

다음 코드에서는 System.Drawing 네임스페이스를 사용합니다.

protected override void OnPaint(PaintEventArgs e)
{
    // Call the OnPaint method of the base class.
    base.OnPaint(e);

    // Declare and instantiate a new pen that will be disposed of at the end of the method.
    using var myPen = new Pen(Color.Aqua);

    // Create a rectangle that represents the size of the control, minus 1 pixel.
    var area = new Rectangle(new Point(0, 0), new Size(this.Size.Width - 1, this.Size.Height - 1));

    // Draw an aqua rectangle in the rectangle represented by the control.
    e.Graphics.DrawRectangle(myPen, area);
}
Protected Overrides Sub OnPaint(e As PaintEventArgs)
    MyBase.OnPaint(e)

    ' Declare and instantiate a drawing pen.
    Using myPen = New System.Drawing.Pen(Color.Aqua)

        ' Create a rectangle that represents the size of the control, minus 1 pixel.
        Dim area = New Rectangle(New Point(0, 0), New Size(Me.Size.Width - 1, Me.Size.Height - 1))

        ' Draw an aqua rectangle in the rectangle represented by the control.
        e.Graphics.DrawRectangle(myPen, area)

    End Using
End Sub

기본 Control 클래스의 OnPaint 메서드는 그리기 기능을 구현하지 않고 단순히 Paint 이벤트에 등록된 이벤트 대리자를 호출합니다. OnPaint를 재정의할 때는 일반적으로 등록된 대리자가 Paint 이벤트를 받도록 기본 클래스의 OnPaint 메서드를 호출해야 합니다. 그러나 전체 화면을 그리는 컨트롤은 깜박임이 발생하므로 기본 클래스의 OnPaint를 호출하면 안 됩니다.

참고

컨트롤에서 직접 OnPaint를 호출하는 대신, Control에서 상속받은 Invalidate 메서드 또는 Invalidate를 호출하는 다른 메서드를 호출합니다. 그러면 Invalidate 메서드가 OnPaint를 호출합니다. Invalidate 메서드가 오버로드되고 Invalidatee에 제공된 인수에 따라 화면 영역의 일부 또는 전체를 다시 그립니다.

컨트롤의 OnPaint 메서드 코드는 컨트롤을 처음 그릴 때와 컨트롤을 새로 고칠 때마다 실행됩니다. 크기를 조정할 때마다 컨트롤을 다시 그리려면 컨트롤의 생성자에 다음 줄을 추가합니다.

SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.ResizeRedraw, True)

OnPaintBackground

기본 Control 클래스는 그리기에 유용한 다른 메서드인 OnPaintBackground 메서드를 정의합니다.

protected virtual void OnPaintBackground(PaintEventArgs e);
Protected Overridable Sub OnPaintBackground(e As PaintEventArgs)

OnPaintBackground는 창의 배경(및 모양)을 그리고 속도가 빠른 반면, OnPaint는 세부 정보를 그리고 개별 그리기 요청이 다시 그려야 하는 모든 영역을 포함하는 하나의 Paint 이벤트로 결합되므로 속도가 더 느릴 수 있습니다. 예를 들어 컨트롤의 그라데이션 색 배경을 그리려는 경우 OnPaintBackground를 호출하는 것이 좋습니다.

OnPaintBackground는 이벤트와 유사하게 명명되고 OnPaint 메서드와 동일한 인수를 사용하는 반면, OnPaintBackground는 진정한 이벤트 메서드가 아닙니다. PaintBackground 이벤트는 없으며, OnPaintBackground는 이벤트 대리자를 호출하지 않습니다. OnPaintBackground 메서드를 재정의할 때는 기본 클래스의 OnPaintBackground 메서드를 호출하기 위한 파생 클래스가 필요하지 않습니다.

GDI+ 기본 사항

Graphics 클래스는 원, 삼각형, 원호, 타원 등의 다양한 도형을 그리는 메서드와 텍스트를 표시하는 메서드를 제공합니다. System.Drawing 네임스페이스에는 도형(원, 사각형, 원호 등), 색, 글꼴, 브러시 등의 그래픽 요소를 캡슐화하는 네임스페이스와 클래스가 포함되어 있습니다.

그리기 영역의 기하 도형

컨트롤의 ClientRectangle 속성은 사용자 화면에서 컨트롤이 사용할 수 있는 사각형 영역을 지정하는 반면, PaintEventArgsClipRectangle 속성은 그려지는 영역을 지정합니다. 컨트롤 표시의 작은 섹션이 변경된 경우와 같이 컨트롤이 사용 가능한 영역의 일부만 그려야 할 수도 있습니다. 이 경우에는 컨트롤 개발자가 그릴 실제 사각형을 컴퓨팅한 후 Invalidate에 전달해야 합니다. Rectangle 또는 Region을 인수로 사용하는 Invalidate의 오버로드된 버전은 해당 인수를 사용하여 PaintEventArgsClipRectangle 속성을 생성합니다.

그래픽 리소스 해제

그래픽 개체는 시스템 리소스를 사용하기 때문에 비용이 많이 듭니다. 해당 개체에는 System.Drawing.Graphics 클래스 인스턴스와 System.Drawing.Brush, System.Drawing.Pen, 기타 그래픽 클래스 인스턴스가 포함됩니다. 필요할 때만 그래픽 리소스를 만들고 사용을 마치면 바로 해제해야 합니다. IDisposable 인터페이스를 구현하는 형식의 인스턴스를 만드는 경우 사용을 마치면 해당 Dispose 메서드를 호출하여 리소스를 해제합니다.

참고 항목