在控制項上小畫家和繪圖 (Windows Forms .NET)

控制項的自訂繪製是 Windows Forms 所簡化的許多複雜工作之一。 撰寫自訂控制項時,有許多選項可用來處理控制項的圖形化外觀。 如果您要撰寫 自訂控制項,也就是繼承自 Control 的控制項 ,您必須提供程式碼來呈現其圖形標記法。

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

如果您要建立 複合控制項 ,也就是繼承自 UserControl 或其中一個現有 Windows Forms 控制項的 控制項 ,您可以覆寫標準圖形標記法,並提供您自己的圖形程式碼。

如果您想要為現有的控制項提供自訂轉譯,而不需要建立新的控制項,您的選項會變得更有限。 不過,您的控制項和應用程式仍有各種不同的圖形化可能性。

下列元素涉及控制項轉譯:

  • 基類 System.Windows.Forms.Control 所提供的繪圖功能。
  • GDI 圖形庫的基本元素。
  • 繪圖區域的幾何。
  • 釋放圖形資源的程式。

控制項提供的繪圖

基類 Control 會透過其 Paint 事件提供繪圖功能。 每當控制項需要更新其顯示時, Paint 就會引發 事件。 如需 .NET 中事件的詳細資訊,請參閱 處理和引發事件

事件的事件 PaintEventArgs 資料類別 Paint 會保存繪製控制項所需的資料 - 繪圖物件的控制碼,以及代表要繪製之區域的矩形。

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 是封裝繪圖功能的 Managed 類別,如本文稍後的 GDI 討論中所述。 ClipRectangle是 結構的實例, Rectangle 並定義控制項可以繪製的可用區域。 控制項開發人員可以使用 控制項的 屬性來計算 ClipRectangleClipRectangle ,如本文稍後的 geometry 討論中所述。

OnPaint

控制項必須覆寫繼承自 Control 的方法, OnPaint 以提供轉譯邏輯。 OnPaint 會取得繪圖物件的存取權,以及要透過 Graphics 傳遞至繪圖物件的 實例屬性來 ClipRectangle 繪製的 PaintEventArgs 矩形。

下列程式碼會 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

OnPaintControl 類的 方法不會實作任何繪圖功能,而只會叫用向 Paint 事件註冊的事件委派。 當您覆寫 OnPaint 時,通常應該叫 OnPaint 用基類的 方法,讓已註冊的委派接收 Paint 事件。 不過,繪製其整個介面的控制項不應該叫用基類 的 OnPaint ,因為這樣會引入閃爍。

注意

請勿直接從控制項叫 OnPaint 用 ;相反地,請叫 Invalidate 用 方法(繼承自 Control )或其他叫用 的方法 Invalidate 。 方法 Invalidate 接著會叫用 OnPaint 。 方法 Invalidate 會多載,而且,視提供給 的 Invalidatee 引數而定,會重繪其部分或所有螢幕區域。

控制項方法中的 OnPaint 程式碼會在第一次繪製控制項時執行,每當重新整理時就會執行。 若要確保您的控制項每次調整大小都會重新繪製,請將下列這一行新增至控制項的建構函式:

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

On小畫家Background

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 的 屬性會指定使用者畫面上控制項可用的矩形區域,而 ClipRectanglePaintEventArgs 屬性則指定繪製的區域。 控制項可能需要只繪製其可用區域的一部分,就像控制項的顯示社區段變更時的情況一樣。 在這些情況下,控制項開發人員必須計算實際矩形來繪製,並將該矩形傳遞至 Invalidate 。 採用 或 Region 做為引數的多 Rectangle 載版本 Invalidate 會使用該引數來產生 ClipRectanglePaintEventArgs 屬性。

釋放圖形資源

繪圖物件很昂貴,因為它們使用系統資源。 這類物件包括 類別的 System.Drawing.Graphics 實例,以及 、 System.Drawing.Pen 和其他圖形類別的實例 System.Drawing.Brush 。 請務必只在需要圖形資源時建立圖形資源,並在使用完畢後立即釋放它。 如果您建立實作 介面的類型 IDisposable 實例,請在完成時呼叫其 Dispose 方法以釋放資源。

另請參閱