呈現 Windows Form 控制項
轉譯指的是在使用者螢幕上建立視覺表示法的流程。 Windows Forms 使用 GDI (新的 Windows 圖形庫) 進行轉譯。 提供 GDI 存取的受控類別位於 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 是封裝繪圖功能的受控類別,如本主題稍後的 GDI 討論中所述。 ClipRectangle 是 Rectangle 結構的執行個體,並定義控制項可在其中繪圖的可用區域。 控制項開發人員可以使用控制項的 ClipRectangle 屬性來計算 ClipRectangle,如本主體稍後的幾何討論中所述。
控制項必須覆寫繼承自 OnPaint 的 Control 方法,以提供轉譯邏輯。 OnPaint 透過傳遞給它之 Graphics 執行個體的 ClipRectangle 屬性和 PaintEventArgs 屬性,來存取圖形物件和可在其中繪圖的矩形。
Protected Overridable Sub OnPaint(pe As PaintEventArgs)
protected virtual void OnPaint(PaintEventArgs pe);
基底 OnPaint 類別的 Control 方法不會實作任何繪圖功能,而只會叫用向 Paint 事件註冊的事件委派。 當您覆寫 OnPaint 時,您一般應該叫用基底類別的 OnPaint 方法,以便已註冊的委派可以接收 Paint 事件。 不過,繪製其整個表面的控制項不應該叫用基底類別的 OnPaint,因為這會導致閃爍。 如需覆寫 OnPaint 事件的範例,請參閱 如何:建立顯示進度的 Windows Forms 控制項。
注意
請勿直接從控制項叫用 OnPaint;請改為叫用 Invalidate 方法 (繼承自 Control),或叫用 Invalidate 的一些其他方法。
Invalidate 方法會接著叫用 OnPaint。
Invalidate 方法會多載,而且,視提供給 Invalidatee
的引數而定,控制項會重新繪製其部分或所有螢幕區域。
基底 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 方法時,不需要衍生類別即可叫用其基底類別的 OnPaintBackground 方法。
GDI+ 基本概念
Graphics 類別提供繪製各種圖形 (例如圓形、三角形、弧線和橢圓形) 的方法,以及顯示文字的方法。 System.Drawing 命名空間及其子命名空間包還類別,其會封裝圖形元素,例如圖形 (圓形、矩形、弧線等)、色彩、字型、筆刷等。 如需 GDI 的詳細資訊,請參閱使用 Managed Graphics 類別。 GDI 的基本概念也說明於如何:建立顯示進度的 Windows Forms 控制項。
繪圖區域的幾何
控制項的 ClientRectangle 屬性會指定使用者螢幕上可供控制項使用的矩形區域,而 ClipRectangle 的 PaintEventArgs 屬性則會指定實際繪圖的區域。 (請記住,繪製是在採用 Paint 執行個體作為引數的 PaintEventArgs 事件方法中完成的)。 控制項可能只需要繪製其可用區域的一部分,就像控制項的小區段顯示變更時的情況一樣。 在那些情況下,控制項開發人員必須計算實際矩形,以在其中繪圖並傳遞至 Invalidate。 接受 Invalidate 或 Rectangle 做為引數的 Region 多載版本會使用該引數來產生 ClipRectangle 的 PaintEventArgs 屬性。
下列程式碼段顯示 FlashTrackBar
自訂控制項如何計算要繪製的矩形區域。
client
變數表示 ClipRectangle 屬性。 如需完整的範例,請參閱如何:建立顯示進度的 Windows Forms 控制項。
Rectangle invalid = new Rectangle(
client.X + min,
client.Y,
max - min,
client.Height);
Invalidate(invalid);
Dim invalid As Rectangle = New Rectangle( _
client.X + lmin, _
client.Y, _
lmax - lmin, _
client.Height)
Invalidate(invalid)
釋放圖形資源
圖形物件的成本高昂,因為它們會使用系統資源。 此類物件包括 System.Drawing.Graphics 類別的執行個體,以及 System.Drawing.Brush、System.Drawing.Pen 和其他圖形類別的執行個體。 請務必只在需要圖形資源時建立圖形資源,並在使用完畢後立即釋放它。 如果您建立實作 IDisposable 介面的類型,請在完成時呼叫其 Dispose 方法,以釋放資源。
下列程式碼段顯示 FlashTrackBar
自訂控制項如何建立及釋放 Brush 資源。 如需完整的原始程式碼,請參閱如何:建立顯示進度的 Windows Forms 控制項。
private Brush baseBackground = null;
Private baseBackground As Brush
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);
}
}
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
protected override void OnResize(EventArgs e) {
base.OnResize(e);
if (baseBackground != null) {
baseBackground.Dispose();
baseBackground = null;
}
}
Protected Overrides Sub OnResize(ByVal e As EventArgs)
MyBase.OnResize(e)
If (baseBackground IsNot Nothing) Then
baseBackground.Dispose()
baseBackground = Nothing
End If
End Sub