DataGridViewに複数行で結合した列の表題を表示する
DataGridView に、2 行 3 列で、1 行目が結合した以下のような表題を表示してみます。DataGridViewのCellPaintingイベントで、罫線や文字列を描画します。
+--------------------------------------+ | 結合された1行目の表題 | +------------+------------+------------+ | 1列目の表題 | 2列目の表題 | 3列目の表題| +------------+------------+------------+
Form には dataGridView1 という名前の DataGridView を配置しておきます。次に示すのは Form のコンストラクタです。ここでは、
- DataGridView に 3 列追加します。
- 列の表題の高さを自動調整しないように設定します。
- CellPainting イベントハンドラを設定します。
public Form1() { // Form には dataGridView1 という名前の DataGridView を配置しておきます。 InitializeComponent(); // DataGridView に 3 列追加します。 DataGridViewTextBoxColumn[] columns = { new DataGridViewTextBoxColumn() {HeaderText = "1列目の表題"}, new DataGridViewTextBoxColumn() {HeaderText = "2列目の表題"}, new DataGridViewTextBoxColumn() {HeaderText = "3列目の表題"} }; dataGridView1.Columns.AddRange(columns); // 列の表題の高さを自動調整しないように設定します。 dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing; dataGridView1.ColumnHeadersHeight = 50; // CellPainting イベントハンドラを設定します。 dataGridView1.CellPainting += CellPainting; }
CellPainting イベントハンドラの最初の部分です。描画する表題セル以外はここで戻り、通常通り DataGridView に描画してもらいます。
/// <summary> /// セルの描画が必要な場面で呼び出されるイベント。 /// </summary> private void CellPainting(Object sender, DataGridViewCellPaintingEventArgs e) { // 描画する表題セル以外はここで戻り、通常通り DataGridView に描画してもらう。 if (e.RowIndex != -1 || e.ColumnIndex < 0) { return; }
ここからは、表示を変更する表題セルを描画してゆきます。まずは、結合させる一番左のセルの左側の X 座標と、一番右のセルの右側の X 座標を求めます。
// 結合させる一番左のセルの左側の X 座標を求める。 int mergedLeftX = e.CellBounds.X; for (int li = e.ColumnIndex - 1; li >= 0; --li) { DataGridViewColumn col = dataGridView1.Columns[li]; mergedLeftX -= col.Width; } // 結合させる一番右のセルの右側の X 座標を求める。 int mergedRightX = e.CellBounds.X + e.CellBounds.Width - 1; for (int ri = e.ColumnIndex + 1; ri < dataGridView1.Columns.Count; ++ri) { DataGridViewColumn col = dataGridView1.Columns[ri]; mergedRightX += col.Width; }
求めた座標を使って、2つのRectangleを作成します。
- 結合させるセルの 1 行目の範囲 (3 つのセルの上半分) の長方形
- ペイントするセルの 2 行目の範囲 (このセルの下半分) の長方形
// 結合させるセルの 1 行目の範囲 (3 つのセルの上半分) の長方形を作成する。 int mergedWidth = mergedRightX - mergedLeftX + 1; int firstLineHeight = e.CellBounds.Height / 2; Rectangle mergedFirstLineRect = new Rectangle( mergedLeftX - 1, e.CellBounds.Y, mergedWidth, firstLineHeight); // ペイントするセルの 2 行目の範囲 (このセルの下半分) の長方形を作成する。 int secondLineHeight = e.CellBounds.Height - firstLineHeight; Rectangle secondLineRect = new Rectangle( e.CellBounds.X - 1, e.CellBounds.Y + firstLineHeight, e.CellBounds.Width, secondLineHeight - 1);
作成した長方形を背景色で塗りつぶし、境界の線を引きます。
// 作成した長方形を背景色で塗りつぶす。 Brush bgBrush = new SolidBrush(e.CellStyle.BackColor); e.Graphics.FillRectangle(bgBrush, mergedFirstLineRect); e.Graphics.FillRectangle(bgBrush, secondLineRect); // 境界の線を引く。 Color borderColor = dataGridView1.GridColor; Pen borderPen = new Pen(borderColor); e.Graphics.DrawRectangle(borderPen, mergedFirstLineRect); e.Graphics.DrawRectangle(borderPen, secondLineRect);
文字列を左揃え、上下方向は真ん中、左右のパッドあり、で描きます。
// 文字列を左揃え、上下方向は真ん中、左右のパッドあり、で描く。 String firstLineText = "結合された1行目の表題"; String secondLineText = e.FormattedValue.ToString(); Font font = e.CellStyle.Font; Color fgColor = e.CellStyle.ForeColor; TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.LeftAndRightPadding; TextRenderer.DrawText( e.Graphics, firstLineText, font, mergedFirstLineRect, fgColor, flags); TextRenderer.DrawText( e.Graphics, secondLineText, font, secondLineRect, fgColor, flags);
最後に e.Handled を true に設定し、DataGridView が描画しないようにします。
// 描画したことを示す。DataGridView は描画しない。 e.Handled = true; }
以下のような課題があります。
- 結合した列の文字列は左揃えのみ -- 列の幅が変更された場合、幅が変更された列とその右側の列が再描画されるようです。幅が変更された列より左側は、表示が変わらないため再描画されません。結合した列の文字列が中央揃えや右揃えの場合、列幅変更の影響を受けない部分が再描画されず、表示が乱れます。
- 表題の高さの自動調整 -- 列幅を変更しても表題の高さは自動調整されません。
- 列のソート順のグリフ表示など -- このプログラムでは描画しておらず、必要ならば描画するプログラムの作成が必要です。