繪製控制項 (Windows Forms .NET)

控制項的自訂繪製是 Windows Forms 所簡化的許多複雜工作之一。 製作自訂控制項時,有許多選項可用來處理控制項的圖形化外觀。 如果您要製作自訂控制項 (部分機器翻譯),也就是繼承自 Control 的控制項,您必須提供程式碼來轉譯其圖形表示法。

如果您要建立複合控制項 (部分機器翻譯),也就是繼承自 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 討論中所述。 ClipRectangle (部分機器翻譯) 是 Rectangle 結構 (部分機器翻譯) 的執行個體,並定義控制項可在其中繪圖的可用區域。 控制項開發人員可以使用控制項的 ClipRectangle 屬性 (部分機器翻譯) 來計算 ClipRectangle (部分機器翻譯),如本文稍後的幾何討論中所述。

OnPaint

控制項必須覆寫繼承自 Control (部分機器翻譯) 的 OnPaint 方法 (部分機器翻譯),以提供轉譯邏輯。 OnPaint 透過傳遞給它之 PaintEventArgs 執行個體 (部分機器翻譯) 的 Graphics 屬性 (部分機器翻譯) 和 ClipRectangle 屬性,來存取圖形物件和可在其中繪圖的矩形。

下列程式碼使用 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 時,您一般應該叫用基底類別的 OnPaint 方法 (部分機器翻譯),以便已註冊的委派可以接收 Paint 事件 (部分機器翻譯)。 不過,繪製其整個表面的控制項不應該叫用基底類別的 OnPaint (部分機器翻譯),因為這會導致閃爍。

注意

請勿直接從控制項叫用 OnPaint (部分機器翻譯);請改為叫用 Invalidate 方法 (部分機器翻譯)(繼承自 Control (部分機器翻譯)),或叫用 Invalidate (部分機器翻譯) 的一些其他方法。 Invalidate 方法 (部分機器翻譯) 會接著叫用 OnPaint (部分機器翻譯)。 Invalidate 方法會多載,而且,視提供給 Invalidate e 的引數而定,會重新繪製其部分或所有螢幕區域。

控制項 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 屬性 (英文) 會指定使用者螢幕上可供控制項使用的矩形區域,而 PaintEventArgs (部分機器翻譯) 的 ClipRectangle 屬性 (部分機器翻譯) 則會指定繪圖的區域。 控制項可能只需要繪製其可用區域的一部分,就像控制項的小區段顯示變更時的情況一樣。 在那些情況下,控制項開發人員必須計算實際矩形,以在其中繪圖並傳遞至 Invalidate (部分機器翻譯)。 接受 Rectangle (部分機器翻譯) 或 Region (部分機器翻譯) 做為引數的 Invalidate 多載版本 (部分機器翻譯) 會使用該引數來產生 PaintEventArgs (部分機器翻譯) 的 ClipRectangle 屬性 (部分機器翻譯)。

釋放圖形資源

圖形物件的成本高昂,因為它們會使用系統資源。 此類物件包括 System.Drawing.Graphics 類別 (英文) 的執行個體,以及 System.Drawing.Brush (英文)、System.Drawing.Pen (英文) 和其他圖形類別的執行個體。 請務必只在需要圖形資源時建立圖形資源,並在使用完畢後立即釋放它。 如果您建立實作 IDisposable 介面 (部分機器翻譯) 的類型執行個體,請在使用完畢後呼叫其 Dispose 方法 (英文) 以釋放資源。

另請參閱