呈現 Windows Form 控制項

呈現意指在使用者螢幕上建立視覺表現的過程。 Windows Form 使用 GDI (新的 Windows 圖庫) 來呈現。 提供對 GDI 存取的 Managed 類別是位於 System.Drawing 命名空間和它的子命名空間。

下列項目涉及控制項的呈現。

  • 基底類別 System.Windows.Forms.Control 所提供的繪圖功能。

  • GDI 圖庫的基本項目。

  • 繪圖區域的幾何形狀。

  • 釋放圖形資源的程序。

控制項提供的繪圖功能

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

Paint 事件的事件資料類別 PaintEventArgs 儲存繪製控制項所需的資料 — 圖形物件的控制代碼和代表要繪入的區域的矩形物件。 這些物件會以粗體顯示在下列程式碼片段中。

Public Class PaintEventArgs
   Inherits EventArgs
   Implements IDisposable
   
   Public ReadOnly Property ClipRectangle() As System.Drawing.Rectangle
      ...
   End Property
   
   Public ReadOnly Property Graphics() As System.Drawing.Graphics
      ...
   End Property
   ' Other properties and methods.
   ...
End Class
public class PaintEventArgs : EventArgs, IDisposable {
public System.Drawing.Rectangle ClipRectangle {get;}
public System.Drawing.Graphics Graphics {get;}
// Other properties and methods.
...
}

Graphics 為 Managed 類別,會封裝本主題稍後在 GDI 討論中說明的繪圖功能。 ClipRectangleRectangle 結構的執行個體,並定義控制項能夠繪入的可用區域。 控制項開發人員可以使用控制項的 ClipRectangle 屬性來計算 ClipRectangle,如本主題稍後的幾何形狀討論中所說明的。

控制項必須藉由覆寫繼承自 ControlOnPaint 方法來提供呈現邏輯。 OnPaint 會透過傳遞至它的 PaintEventArgs 執行個體的 GraphicsClipRectangle 屬性,取得對要繪入之圖形物件和方框的存取。

Protected Overridable Sub OnPaint(pe As PaintEventArgs)
protected virtual void OnPaint(PaintEventArgs pe);

基底 Control 類別的 OnPaint 方法不實作任何繪圖功能,而只是叫用 (Invoke) 使用 Paint 事件註冊的事件委派 (Delegate)。 當您覆寫 OnPaint 時,您基本上應該叫用基底類別的 OnPaint 方法,以便註冊的委派接收 Paint 事件。 然而,繪製整個平面的控制項不應該會叫用基底類別的 OnPaint,因為這會造成閃動。 如需覆寫 OnPaint 事件的範例,請參閱 HOW TO:建立顯示進度的 Windows Form 控制項

注意事項注意事項

不要直接從您的控制項叫用 OnPaint;反而要叫用 Invalidate 方法 (繼承自 Control) 或某個叫用 Invalidate 的其他方法。 Invalidate 方法會接著叫用 OnPaintInvalidate 方法為多載,並且取決於供應給 Invalidate e 的引數,控制項將重繪其螢幕區域的局部或全部。

基底 Control 類別會定義另一個對繪圖有用處的方法 — OnPaintBackground 方法。

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

OnPaintBackground 會繪製視窗的背景 (和附帶的形狀),並保證速度很快;OnPaint 則繪製細節,但可能很緩慢,因為個別的繪製要求會組合成一個 Paint 事件以覆蓋所有必須重繪的區域。 舉例來說,如果想為控制項繪製漸層色彩的背景,您可能會想要叫用 OnPaintBackground

雖然 OnPaintBackground 具有類似事件的命名方式,而且接受和 OnPaint 方法相同的引數,但 OnPaintBackground 並不是真正的事件方法。 沒有 PaintBackground 事件,而 OnPaintBackground 也不叫用事件委派。 覆寫 OnPaintBackground 方法時,衍生類別 (Derived Class) 不需要叫用其基底類別的 OnPaintBackground 方法。

GDI+ 基礎

Graphics 類別提供繪製各種圖形 (例如圓形、三角形、弧形和橢圓形) 的方法,以及顯示文字的方法。 System.Drawing 命名空間和它的子命名空間包含有類別,可封裝圖形項目,例如形狀 (例如圓形、三角形、弧形和其他)、色彩、字型、筆刷等等。 如需 GDI 的詳細資訊,請參閱使用 Managed 圖形類別。 GDI 的基本資訊在 HOW TO:建立顯示進度的 Windows Form 控制項 中也有說明。

繪圖區域的幾何學

控制項的 ClientRectangle 屬性會指定使用者螢幕上控制項可用的矩形區域,而 PaintEventArgsClipRectangle 屬性則指定實際繪製的區域 (請記住,繪製是在接受 PaintEventArgs 執行個體做為其引數的 Paint 事件方法中完成)。 控制項可能只需繪製其可用區域的一部分,正如在控制項的一小塊顯示變更時。 在那些場合,控制項開發人員必須計算實際要繪入的矩形,並將它傳遞給 Invalidate。 接受 RectangleRegion 做為引數的 Invalidate 多載版本,會使用該引數來產生 PaintEventArgsClipRectangle 屬性。

下列程式碼範例片段示範 FlashTrackBar 自訂控制項如何計算要繪入的矩形區域。 client 變數代表 ClipRectangle 屬性。 如需完整範例,請參閱 HOW TO:建立顯示進度的 Windows Form 控制項

Dim invalid As Rectangle = New Rectangle( _
    client.X + lmin, _
    client.Y, _
    lmax - lmin, _
    client.Height)

Invalidate(invalid)
Rectangle invalid = new Rectangle(
    client.X + min, 
    client.Y, 
    max - min, 
    client.Height);

Invalidate(invalid);

釋放圖形資源

圖形物件很耗費資源,因為它們使用系統資源。 這些物件包括 System.Drawing.Graphics 類別的執行個體、System.Drawing.Brush 的執行個體、System.Drawing.Pen 以及其他圖形類別。 您只有需要時才建立圖形資源,並且只要使用完畢即釋出,這是很重要的。 如果您建立實作 IDisposable 介面的型別,請在完成時呼叫其 Dispose 方法,以便釋放資源。

下列程式碼片段示範 FlashTrackBar 自訂控制項如何建立並釋出 Brush 資源。 如需完整的原始程式碼,請參閱 HOW TO:建立顯示進度的 Windows Form 控制項

Private baseBackground As Brush
private Brush baseBackground = null;
MyBase.OnPaint(e)

If (baseBackground Is Nothing) Then

    If (myShowGradient) Then
        baseBackground = New LinearGradientBrush(New Point(0, 0), _
                                                 New Point(ClientSize.Width, 0), _
                                                 StartColor, _
                                                 EndColor)
    ElseIf (BackgroundImage IsNot Nothing) Then
        baseBackground = New TextureBrush(BackgroundImage)
    Else
        baseBackground = New SolidBrush(BackColor)
    End If

End If
base.OnPaint(e);
if (baseBackground == null) {
    if (showGradient) {
        baseBackground = new LinearGradientBrush(new Point(0, 0),
                                                 new Point(ClientSize.Width, 0),
                                                 StartColor,
                                                 EndColor);
    }
    else if (BackgroundImage != null) {
        baseBackground = new TextureBrush(BackgroundImage);
    }
    else {
        baseBackground = new SolidBrush(BackColor);
    }
}
Protected Overrides Sub OnResize(ByVal e As EventArgs)
    MyBase.OnResize(e)
    If (baseBackground IsNot Nothing) Then
        baseBackground.Dispose()
        baseBackground = Nothing
    End If
End Sub
protected override void OnResize(EventArgs e) {
    base.OnResize(e);
    if (baseBackground != null) {
        baseBackground.Dispose();
        baseBackground = null;
    }
}

請參閱

工作

HOW TO:建立顯示進度的 Windows Form 控制項