Windows フォーム コントロールのレンダリング
レンダリングとは、ユーザーの画面にコントロールのビジュアル表現を作成する操作です。Windows フォームは、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 を算出できます。これについては、このトピックの後半のジオメトリのセクションで説明します。
コントロールは、Control から継承する OnPaint メソッドをオーバーライドすることによって、レンダリング ロジックを提供する必要があります。OnPaint は、グラフィックス オブジェクトと四角形へアクセスし、渡された PaintEventArgs インスタンスの Graphics プロパティと ClipRectangle プロパティを使用してこれらのオブジェクトを描画します。
Protected Overridable Sub OnPaint(pe As PaintEventArgs)
protected virtual void OnPaint(PaintEventArgs pe);
Control 基本クラスの OnPaint メソッドは描画機能を実装しません。このメソッドは、Paint イベントに登録されているイベント デリゲートを呼び出すだけです。OnPaint をオーバーライドする場合は、登録デリゲートが Paint イベントを受信できるように、常に基本クラスの OnPaint メソッドを呼び出す必要があります。ただし描画面全体を描画するコントロールでは、基本クラスの OnPaint を呼び出すとちらつきが発生するため、これを呼び出さないようにします。OnPaint イベントのオーバーライドの例については、「方法 : 進行状況を示す Windows フォーム コントロールを作成する」を参照してください。
注意
コントロールから直接 OnPaint を呼び出さないでください。Control から継承された Invalidate メソッドを呼び出すか、または Invalidate を呼び出す他のメソッドを呼び出してください。Invalidate メソッドが OnPaint を呼び出します。Invalidate メソッドはオーバーロードされます。また、Invalidate メソッドに渡される引数によって、コントロールの描画領域が画面領域の全体または一部のどちらであるかが決まります。
Control 基本クラスは、描画に役立つもう 1 つのメソッドである OnPaintBackground メソッドを定義します。
Protected Overridable Sub OnPaintBackground(pevent As PaintEventArgs)
protected virtual void OnPaintBackground(PaintEventArgs pevent);
OnPaintBackground はウィンドウの背景 (ウィンドウの形状) を描画するメソッドであり、高速処理が保証されています。一方、OnPaint は詳細を描画するメソッドです。個々の描画要求が 1 つの Paint イベントに結合されますが、このイベントは再描画する必要のある領域をすべてカバーしているため、このメソッドの処理には時間がかかることがあります。たとえば、コントロールのグラデーション色の背景を描画するには、OnPaintBackground を呼び出します。
OnPaintBackground にはイベントに似た命名規則があり、OnPaint メソッドと同じ引数を受け取ります。ただし、OnPaintBackground は厳密にはイベント メソッドではありません。PaintBackground というイベントは存在せず、OnPaintBackground はイベント デリゲートを呼び出しません。OnPaintBackground メソッドをオーバーライドする場合は、派生クラスがその基本クラスの OnPaintBackground メソッドを呼び出す必要はありません。
GDI+ の基本事項
Graphics クラスには、テキストを表示するメソッドと同様に円形、三角形、円弧、楕円形などのさまざまな形状を描画するメソッドがあります。形状 (円形、四角形、円弧など)、色、フォント、ブラシなどのグラフィックス要素をカプセル化したクラスは、System.Drawing 名前空間とその下位名前空間に格納されています。GDI の詳細については、「マネージ グラフィックス クラスの使用」を参照してください。また、GDI の基本については「方法 : 進行状況を示す Windows フォーム コントロールを作成する」にも説明されています。
描画領域のジオメトリ
PaintEventArgs の ClipRectangle プロパティが実際に描画される領域を指定している一方、コントロールの ClientRectangle プロパティはユーザーの画面上のコントロールに使用できる四角形の領域を指定します。実際に描画が実行されるのは、PaintEventArgs インスタンスを引数として受け取る Paint イベント メソッドです。コントロールでは、使用できる領域の一部を描画するだけで済む場合があります。たとえば、コントロールの表示領域の一部だけが変更された場合などです。このような場合、コントロールの開発者は実際に描画する領域を計算し、算出された値を Invalidate へ渡す必要があります。引数として Rectangle または Region を受け取る Invalidate のオーバーロードされたバージョンでは、その引数を使用して PaintEventArgs の ClipRectangle プロパティを生成します。
FlashTrackBar
カスタム コントロールが、描画する四角形領域を計算する処理を次のコード片に示します。client
変数は ClipRectangle プロパティを示します。サンプル全体については、「方法 : 進行状況を示す Windows フォーム コントロールを作成する」を参照してください。
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 リソースの作成と解放を、次のコード片に示します。ソース コード全体については、「方法 : 進行状況を示す Windows フォーム コントロールを作成する」を参照してください。
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 Not (BackgroundImage Is 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 Not (baseBackground Is 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;
}
}