サンプルの作成
まず、Visual Studio 2005で新規の[Windowsアプリケーション]プロジェクトを作成します。次に、新しいデータソースを作成します([データ]メニューの[新しいデータソースの追加]をクリックします)。2、3個またはそれ以上の列を含むデータソースを作成します。そのうち1つの列は整数列を選択します。
ここで示すサンプルでは、Northwind ProductsテーブルのProductID、ProductName、UnitsInStockの3つのフィールドを使用します。[データソースの表示]ウィンドウが表示されている状態で(表示されていない場合は[データ]メニューの[データソースの表示]をクリックします)、プロジェクトの単一フォームをフォームデザイナで開き、テーブル全体をこのフォームへドラッグします。Visual Studioによって、フォームにDataGridViewコントロールが自動的に作成されます(DataSet、BindingSource、TableAdapterなど、Windowsフォーム標準のデータバインディング要素も設定されます)。DataGridViewコントロールのスマートタグで、[親コンテナにドッキングする]を選択します。最後に、プロジェクトを保存してフォームを実行し、連結したデータがDataGridViewコントロールにそのまま表示されることを確認します。
これで土台はできました。これ以降、図1と同じフィールドを使用しているものとして説明を進めます。最初の実作業として、まずプロジェクトにDataGridViewBarGraphColumnという新しいクラスを追加します。このクラスではDataGridViewColumnクラスを継承します。このクラスのコードを次のように変更して、後でカスタムセルタイプを作成できるようにスタブを追加しておきます。後でまたこのクラスに戻り、仕上げを行います。
Public Class DataGridViewBarGraphColumn Inherits DataGridViewColumn Public MaxValue As Long Private needsRecalc As Boolean = True Public Sub CalcMaxValue() End Sub End Class
public class DataGridViewBarGraphColumn : DataGridViewColumn { public DataGridViewBarGraphColumn(){} public long MaxValue; private bool needsRecalc = true; public void CalcMaxValue() {} }
次に、今度はDataGridViewBarGraphCellという名前の新しいクラスをプロジェクトに追加します。今回のサンプルでは、標準のテキストボックスセルの動作をエミュレートする必要があるので、このクラスがDataGridViewTextBoxCellクラス(セルの背景や内容を描画する機能を含む)を継承するようにします。C#の場合は、次のコード例のように、ファイルの先頭にusing
ステートメントを追加する必要があります。
Public Class DataGridViewBarGraphCell Inherits DataGridViewTextBoxCell End Class
// Add these to your file: using System.Drawing; using System.Windows.Forms; // Your class should look like this: public class DataGridViewBarGraphCell : DataGridViewTextBoxCell { }
このクラスでは、基本クラスのメソッドのうちPaint
メソッドだけをオーバーライドします。オーバーライドするメソッドの詳細を自分で入力する必要はありません。クラス内にメソッド宣言の一部を入力すると、Visual Studioがどのメソッドかを判断して、自動的に詳細を生成してくれます。次のように入力し、[Tab]キーを押してみましょう。
Overrides Paint
public override Paint
これで、Visual Studioによって宣言の内容が自動的に補充されます。以下は、このページに収まるように編集し直したものです(コードを読みやすくするために、関係のない名前空間参照も削除しました)。
Protected Overrides Sub Paint( _ ByVal graphics As Graphics, _ ByVal clipBounds As Rectangle, _ ByVal cellBounds As Rectangle, _ ByVal rowIndex As Integer, _ ByVal cellState As DataGridViewElementStates, _ ByVal value As Object, _ ByVal formattedValue As Object, _ ByVal errorText As String, _ ByVal cellStyle As DataGridViewCellStyle, _ ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _ ByVal paintParts As DataGridViewPaintParts) MyBase.Paint(graphics, clipBounds, cellBounds, _ rowIndex, cellState, value, _ formattedValue, errorText, cellStyle, _ advancedBorderStyle, paintParts) End Sub
protected override void Paint( Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); }
このコードを見てもわかるように、グリッドの各セルの描画時には、DataGridViewコントロールからDataGridViewTextBoxCellクラスに(ひいてはこのクラスを継承するかカスタムセルクラスにも)大量の情報が渡されます。表1に、このPaint
メソッドのオーバーライドで受け取るパラメータの説明を示します。
パラメータ | 説明 |
graphics | セルの描画時に使用できるGraphicsオブジェクト |
clipBounds | DataGridViewコントロール内で再描画の必要な領域を示すRectangleオブジェクト |
cellBounds | セル内の描画領域を示すRectangleオブジェクト |
rowIndex | 描画対象のセルの行インデックス |
cellState | セルの状態を示すDataGridViewElementStates値(Displayed、Frozen、None、ReadOnly、Resizable、ResizableSet、Selected、Visible)のビットごとの組み合わせ |
value | 描画対象セルのObject型データ |
formattedValue | 描画対象セルの書式設定されたObject型値 |
errorText | セルに関連するエラーメッセージ |
cellStyle | セルの書式とスタイルの情報を含むDataGridViewCellStyleのインスタンス |
advancedBorderStyle | セルの境界線スタイルの情報を含むDataGridViewAdvancedBorderStyleのインスタンス |
paintParts | セルの描画部分を示すDataGridViewPaintParts値(All、Background、Border、ContentBackground、ContentForeground、ErrorIcon、Focus、None、SelectionBackground)のビットごとの組み合わせ |
このサンプルの場合、Paint
メソッドのパラメータの多くは使用する必要がありませんが、もっと複雑なセルタイプを作成する場合にどのようなツールを利用すればよいかをよく把握しておくとよいでしょう。
このサンプルは比較的単純で、横棒グラフと書式設定された値を並べて表示するだけです。表1に示されたパラメータのうち、このサンプルで使用する必要があるのはcellBounds
、cellState
、value
、formattedValue
のみです。
まず、先ほど作成したPaint
メソッドオーバーライド内で、基本クラスのPaint
メソッドの呼び出しを書き換え、パラメータリストからformattedValue
を削除します。この値は独自に描画したいため、基本クラスでは処理されないようにする必要があります。
MyBase.Paint(graphics, clipBounds, cellBounds, _ rowIndex, cellState, _ value, "", errorText, cellStyle, _ advancedBorderStyle, paintParts)
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, "", errorText, cellStyle, advancedBorderStyle, paintParts);
次に、セルの値を取得するコードを追加します。値がDBNullの場合は0として処理します。値が0の場合は1に変更します(このようにすることで、値が0でも1ピクセル幅の縦棒が表示されます)。このようにする必要がなければ、そのままの単純な変換にしてもかまいません。
' Get the value of the cell: Dim cellValue As Decimal If IsDBNull(value) Then cellValue = 0 Else cellValue = CDec(value) End If ' If cell value is 0, you still want to ' show something, so set the value to 1. If cellValue = 0 Then cellValue = 1 End If
// Get the value of the cell: decimal cellValue = 0; if (Convert.IsDBNull(value)) cellValue = 0; else cellValue = Convert.ToDecimal(value); // If cell value is 0, you still want to // show something, so set the value to 1. if (cellValue == 0) cellValue = 1;
左端からのオフセット、および横棒グラフとテキストの間の幅を制御する2つの定数を追加します。この2つの値は、好みに合わせて変更できます。
Const HORIZONTALOFFSET As Integer = 1 Const SPACER As Integer = 4
const int HORIZONTALOFFSET = 1; const int SPACER = 4;