トップ回答者
DataGridViewの2段表示

質問
-
イヨモです。
現在、Windowsフォームのアプリケーションを開発しています。
そこで、ユーザインタフェース上、DataGridViewを2段表示する必要があります。
1つのセルに文字を改行して表示する方法も考えましたが、セルにデータをバインドさせたい場合もあるため、
改行表示では不十分です。
出来れば、GrapeCityで販売されているFlexGridコントロールなどがあれば良いのですが、今回は使用しないため、DataGridViewのカスタムコントロールを作成しようと考えています。
下記図のようなDataGridViewは作成可能なのでしょうか。
よろしくお願い致します。
日付
名前
血液型
項目④
項目⑤
項目⑥
項目⑦
項目⑧
項目⑨
項目⑩
2006/6/14
イヨモ
A
・・・
・・・
・・・
・・・
・・・
・・・
・・・
2006/6/14
・・・
・・・
・・・
・・・
・・・
・・・
・・・
・・・
・・・
※緑部分が列ヘッダー。
回答
-
データ入力をせず、表示するだけなら、できるんじゃないでしょうか? 基本的には自分で描いてあげることになるでしょう。
.NET1.1のDataGridでは実現したことがあります。DataGridViewはDataGridよりもカスタマイズが楽になっていますので、よりやさしく実現できそうなのですが、試したことはありません。
とりあえずとっかかりとして、以下が参考になりそうな気がします。方法 : Windows フォームの DataGridView コントロールの行の外観をカスタマイズする
http://msdn2.microsoft.com/ja-jp/library/85kxk29c.aspx -
# 回答じゃまったくないんですが...
数ヶ月すると,
UI に WPF (Windows Presentation Foundation)
というもの(テクノロジ)が使えるようになります。その WPF だと,グリッドのような繰り返し描画は,ListView というもので表現するんですが,
その行は,ListViewItem という形で持つようになり,
ListViewItem は,WPF 内で,ContentControl と呼ばれているもので,
そのListViewItem には,要素を ひとつ 持つことができます。
ふつうは,ViewBase から派生したものが指定されることを想定しているようです。MS からは,ViewBase というものから派生した GridView というものが用意されていて,
それを ListViewItem に指定すると,今の DataGridView のようになるわけです。
見た目は一緒なんですが,仕組み的にはまったく変わります。-------------------------------------------------------
実際には,試していないので保障はできないんですが,
WPF では,各行の内容 表現/描画 は,簡単にやれるんじゃないかと思います。というのは,
WPF では,ContentControl 系のものには,
その中に別のコントロールを入れ子にしていけます。
で,
Canvas という名前のコントロールも ContentControl なんですが,
Canvas という名前から連想できるように,
その中に入れ子で別のコントロールを複数入れることができます。
それも好きな位置に表示させれます。現在は,拡張しようとすると,自力で描画しないといけません。
でも,WPF だと,相当簡単に 宣言的にやれるようになりそうなので,
WPF の研究をした方が近道のような気がします。たぶん。また,データバインディング自体は,ListView 側で行われるので,
その各行の中身の描写は,ViewBase から派生したクラスで利用する
DataTemplate オブジェクトを利用するだけです。
XAMLフォーマット と呼ばれているもので,
描画位置やバインディング等を指定するだけです。
その指定に従って,繰り返し表示をやってくれます。イメージとしては,
How to: Create a Custom View Mode for a ListView
の
<DataTemplate x:Key="centralTile">
<StackPanel Height="100" Width="90">
<Grid Width="70" Height="70" HorizontalAlignment="Center">
<Image Source="{Binding XPath=@Image}" Margin="6,6,6,9"/>
</Grid>
<TextBlock Text="{Binding XPath=@Name}" FontSize="13"
HorizontalAlignment="Center" Margin="0,0,0,1" />
<TextBlock Text="{Binding XPath=@Type}" FontSize="9"
HorizontalAlignment="Center" Margin="0,0,0,1" />
</StackPanel>
</DataTemplate>の箇所です。ここでは,Canvas でなく StackPanel を使っています。
行のイメージが浮かぶと思います。
こんな風に宣言的にやるだけで,描画位置を調整できるので楽だと思います。# Vista で実現されようとしているものですが,
# もちろん,WinXP 上でも使えるテクノロジです。 -
一部 バグが有りましたので 改良しました
Imports System.Windows.Forms
Imports System.Drawing
Public Class ExDataGridView
Inherits DataGridViewPublic Sub New()
MyBase.new()
End Sub
Public pBorderColor As Color = SystemColors.ControlDark
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("境界線のカラー")> _
Public Property BorderColor() As Color
Get
Return pBorderColor
End Get
Set(ByVal value As Color)
pBorderColor = value
End Set
End PropertyPublic pDokCell As New Generic.List(Of Integer)
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("結合するヘッダーを設定する値 設定する値は1列目から2列分、4列目から3列分結合であれば 2,0,0,3というふうに設定 Generic.List型 ")> _
Public Property ドッキングセル() As Generic.List(Of Integer)
Get
Return pDokCell
End Get
Set(ByVal value As Generic.List(Of Integer))
pDokCell = value
End Set
End PropertyPublic pHedTXT() As String
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("上部ヘッダーテキストです 1列目から2列分結合した部分のテキストを""A""4列目から3列分結合させた部分のテキストを""B""とする場合 A、空白、空白、B というふうに設定" & _
" 空白に設定している列は元のヘッダーテキストが表示される")> _
Public Property FullHedTxt() As String()
Get
Return pHedTXT
End Get
Set(ByVal value As String())
pHedTXT = value
End Set
End PropertyPrivate Sub Me_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles Me.CellPainting
ヘッダー結合(e, pDokCell)
End SubPublic Function HedTxtSet() As ArrayList
Dim arry As New ArrayList
Dim cel As New ArrayList
Dim col As Integer = Me.ColumnCount - 1
For i As Integer = 0 To col
arry(i) = Me.Columns(i).HeaderText
Next
For Each d As Integer In ドッキングセル
For ii As Integer = d To d + ドッキングセル(d) - 1
arry(d) = FullHedTxt(d)
Next
Next
Return arry
End FunctionPublic Event HedPaint()
Private Sub aaExDataGridView_v6_HedPaint() Handles Me.HedPaint
Dim dok As Integer = 0
For Each d As Integer In ドッキングセル
If d > 1 Then
dok = 1
End If
Next
If dok = 1 Then
Me.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
Me.ColumnHeadersHeight = 34
End If
End SubPrivate Sub ヘッダー結合(ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs, _
ByVal Dokcell As Generic.List(Of Integer))RaiseEvent HedPaint()
If Dokcell Is Nothing Then Exit Sub
If e.ColumnIndex >= 0 AndAlso e.RowIndex = -1 Then
Dim cWid As New Hashtable
Dim ww As Integer
For iii As Integer = 0 To CInt(Dokcell.Count) - 1
ww = 0
If Dokcell(iii) <> Nothing ThenFor id As Integer = iii To iii + Dokcell(iii) - 1
ww = ww + Me.Columns(id).Width
Next
cWid(iii + Dokcell(iii) - 1) = ww
End If
NextDim txt As String = CStr(e.Value)
Dim DokSetMain As New ArrayList
Dim DokSub As New ArrayList
Dim DokTxt As New Hashtable
Dim HedTX As New HashtableDim cc As Integer
For Each d As Integer In Dokcell
If d > 1 Then
Dim int As Integer = cc + d - 1
DokSetMain.Add(int)
DokTxt(int) = Me.Columns(cc).HeaderCell.Value
Dim max As Integer
If Not FullHedTxt Is Nothing Then
max = FullHedTxt.Length
End IfIf cc < max Then
HedTX(int) = FullHedTxt(cc)
End IfIf d > 1 Then
For i As Integer = cc To cc + d - 1
DokSub.Add(i)
Next
End If
End If
cc += 1
Next
Dim col As Integer = e.ColumnIndex
Dim x2 As Integer = e.CellBounds.X
Dim Y2 As Integer = e.CellBounds.Y
Dim hei As Integer = CInt(e.CellBounds.Height / 2)
Dim wid As Integer = e.CellBounds.Width
Dim backBrush As New SolidBrush(e.CellStyle.BackColor)
Dim newRect As New Rectangle(e.CellBounds.X, e.CellBounds.Y, _
e.CellBounds.Width - 1, e.CellBounds.Height - 1)
Dim backColorBrush As New SolidBrush(e.CellStyle.BackColor)
Dim gridBrush As New SolidBrush(Me.GridColor)
Dim gridLinePen As New Pen(gridBrush)
Dim BoPen As New Pen(BorderColor)Dim Bou1 As New Rectangle( _
x2 - 1, _
Y2 + hei, _
wid, _
hei - 1)
Try
'ドッキングセル上段
If DokSetMain.Contains(col) = True Thene.Graphics.FillRectangle(backBrush, e.CellBounds)
Dim Bou2 As New Rectangle(x2 - 1, _
Y2 + hei - 1, _
wid, _
hei)
With e.Graphics
.DrawString(CStr(e.Value), e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + hei + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + hei, x2, Y2 + hei + hei - 1)
.DrawLine(Pens.White, x2, Y2 + hei, x2 + wid - 1, Y2 + hei)End With
txt = HedTX(col)
If txt Is Nothing OrElse txt = "" Then
txt = CStr(DokTxt(col))
End IfDim wid2 As Integer = CInt(cWid(col))
x2 = x2 - (wid2 - wid)Bou1 = New Rectangle(x2 - 1, _
Y2, _
wid2, _
hei - 1)
With e.Graphics
.DrawRectangle(BoPen, Bou1)
.DrawRectangle(BoPen, Bou2)
.DrawString(txt, e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + 1, x2, Y2 + hei - 1)
.DrawLine(Pens.White, x2, Y2 + 1, x2 + wid2 - 1, Y2 + 1)
End With
e.Handled = True
Else
'ドッキングセル以外
If DokSub.Contains(col) = False Then
e.Graphics.FillRectangle(backBrush, e.CellBounds)
Bou1 = New Rectangle(x2 - 1, _
Y2, _
wid, _
hei * 2 - 1)
e.Graphics.DrawRectangle(BoPen, Bou1)
Dim max As Integer = 0
If Not FullHedTxt Is Nothing Then
max = FullHedTxt.Length
End If
Dim txt3 As String = Nothing
If col < max Then
txt3 = FullHedTxt(col)
End If
If Not txt3 Is Nothing AndAlso txt3 <> "" Then
txt = txt3
Else
txt = CStr(e.Value)
End If
With e.Graphics
.DrawString(txt, e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + 1, x2, Y2 + hei * 2 - 1)
.DrawLine(Pens.White, x2, Y2 + 1, x2 + wid - 1, Y2 + 1)
End With
e.Handled = True
Else
'ドッキングセル下段
Bou1 = New Rectangle(x2 - 1, _
Y2 + hei - 1, _
wid, _
hei)
With e.Graphics
.FillRectangle(backBrush, e.CellBounds)
.DrawRectangle(BoPen, Bou1)
.DrawString(CStr(e.Value), e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + hei + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + hei, x2, Y2 + hei * 2)
.DrawLine(Pens.White, x2, Y2 + hei, x2 + wid - 1, Y2 + hei)
End With
e.Handled = True
End If
End If
FinallyBoPen.Dispose()
backColorBrush.Dispose()
gridLinePen.Dispose()
gridBrush.Dispose()
backBrush.Dispose()End Try
End IfEnd Sub
End Class
-
かずbooさんのソースを参考に、C#で作成してみました。
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;namespace DataGridViewEx
{
public partial class DataGridViewEx : DataGridView
{
//コンストラクタ
public DataGridViewEx()
{
//セル描画イベントハンドラの追加
this.CellPainting += new DataGridViewCellPaintingEventHandler(DataGridViewEx_CellPainting);
}//ドッキングセルを表す内部クラス
//第0カラムから2カラム分結合し、上段テキストを"A1"とする場合、
//new DataGridViewEx.DockingCell(0, 2, "A1")のようにインスタンスを作成
public class DockingCell
{
//開始セル
private int start;
public int Start
{
get
{
return start;
}
set
{
start = value;
}
}//セル数
private int count;
public int Count
{
get
{
return count;
}
set
{
count = value;
}
}//ヘッダテキスト
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
}
}//コンストラクタ
public DockingCell(int start, int count, string text)
{
this.start = start;
this.count = count;
this.text = text;
}
}//ドッキングセルのリスト
//作成したDockingCell型オブジェクトをAdd()メソッドで追加する
//DockingCellList.Add(new DataGridViewEx.DockingCell(0, 2, "A1"))といった具合
private List<DockingCell> dockingCellList = new List<DockingCell>();
public List<DockingCell> DockingCellList
{
get
{
return dockingCellList;
}
set
{
dockingCellList = value;
}
}//セル描画イベントハンドラ
private void DataGridViewEx_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
//このメソッドでは、ヘッダの描画のみを行う
if (e.ColumnIndex >= 0 && e.RowIndex == -1)
{
//そのヘッダがどのドッキングセルに属しているか調べる
int index = -1;
for (int i = 0; i < DockingCellList.Count; i++)
{
if (e.ColumnIndex >= DockingCellList.Start && e.ColumnIndex < DockingCellList
.Start + DockingCellList
.Count)
{
index = i;
break;
}
}//とりあえず塗りつぶす
e.Graphics.FillRectangle(new SolidBrush(e.CellStyle.BackColor), e.CellBounds);//ドッキングしている場合
if (index >= 0)
{
//上段
int x = e.CellBounds.X;
for (int i = e.ColumnIndex - 1; i >= DockingCellList[index].Start; i--)
{
x -= this.Columns.Width;
}
int width = 0;
for (int i = DockingCellList[index].Start; i < DockingCellList[index].Start + DockingCellList[index].Count; i++)
{
width += this.Columns.Width;
}
Rectangle rect1 = new Rectangle(x, e.CellBounds.Y, width, e.CellBounds.Height / 2);
DrawCell(e.Graphics, rect1);
e.Graphics.DrawString(DockingCellList[index].Text, e.CellStyle.Font, Brushes.Black, rect1.X + 2, rect1.Y + 2);//下段
Rectangle rect2 = new Rectangle(e.CellBounds.X, e.CellBounds.Y + e.CellBounds.Height / 2, e.CellBounds.Width, e.CellBounds.Height / 2);
DrawCell(e.Graphics, rect2);
e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, Brushes.Black, rect2.X + 2, rect2.Y + 2);
}//ドッキングしていない場合
else
{
DrawCell(e.Graphics, e.CellBounds);
e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, Brushes.Black, e.CellBounds.X + 2, e.CellBounds.Y + 2);
}//ハンドルされたことを報告
e.Handled = true;
}
}//セルの描画に用いるメソッド
private void DrawCell(Graphics g, Rectangle rect)
{
g.DrawLine(new Pen(SystemColors.ControlDark), rect.Left - 1, rect.Top, rect.Right - 2, rect.Top);
g.DrawLine(new Pen(SystemColors.ControlDark), rect.Left - 1, rect.Top, rect.Left - 1, rect.Bottom - 1);
g.DrawLine(Pens.White, rect.Left, rect.Top + 1, rect.Right - 2, rect.Top + 1);
g.DrawLine(Pens.White, rect.Left, rect.Top + 1, rect.Left, rect.Bottom - 1);
}
}
} -
窓際族 さんからの引用 datagridview1をexDataGridVIewに変身させることはできませんですよね。
C#でしょうか? C#であればInitializeComponent();という記述がコンストラクタにありますから、そこで右クリックして「定義へ移動」をクリックします。そうするとInitializeComponent()の中に
this.dataGridView1 = new System.Windows.Forms.DataGridView();
という記述が見つかりますから、
this.dataGridView1 = new exDataGridVIew();
とすればdatagridview1がexDataGridVIewに変身します。exDataGridVIewクラスはInitializeComponentから見える位置(スコープ)に記述して下さい。
VBであれば、ドロップダウンよりInitializeComponentを選択して同様に行って下さい。
また、exDataGridVIewをカスタムコントロールにしてしまえば、それをツールボックスに配置し、デザイナで使うことができるようになります。
-
テストプロジェクトを作ってやってみました。
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.Columns.Add("a1", "Team")
DataGridView1.Columns.Add("a2", "Name")
DataGridView1.Columns.Add("a3", "AB")
DataGridView1.Columns.Add("a4", "BA")
DataGridView1.Columns.Add("a5", "SLG")
DataGridView1.Columns.Add("a6", "OPS")
DataGridView1.Columns.Add("a7", "SO")
DataGridView1.Columns(0).Width = 40
DataGridView1.Columns(1).Width = 40
DataGridView1.Columns(2).Width = 40
DataGridView1.Columns(3).Width = 40
DataGridView1.Columns(4).Width = 40
DataGridView1.Columns(5).Width = 40
DataGridView1.Columns(6).Width = 40
Dim GL As New Generic.List(Of Integer)
GL.Add(2)
GL.Add(0)
GL.Add(0)
GL.Add(2)
DataGridView1.ドッキングセル = GL
Dim text() As String = {" Number One", "", "", " Sluger!"}
DataGridView1.FullHedTxt = text
DataGridView1.Rows.Add()
DataGridView1(0, 0).Value = "SEA"
DataGridView1(1, 0).Value = "Ichiro"
DataGridView1(2, 0).Value = 438
DataGridView1(3, 0).Value = 0.345
DataGridView1(4, 0).Value = 0.543
DataGridView1(5, 0).Value = 0.876
DataGridView1(6, 0).Value = 25
End Subこんなんでちゃんと表示されました。
exdatagridviewはとても有用な資産だと思います。
コンポーネントを変更すれば、機能が増えるだけでまったく問題ありません。
ありがとうございあmす。
すべての返信
-
データ入力をせず、表示するだけなら、できるんじゃないでしょうか? 基本的には自分で描いてあげることになるでしょう。
.NET1.1のDataGridでは実現したことがあります。DataGridViewはDataGridよりもカスタマイズが楽になっていますので、よりやさしく実現できそうなのですが、試したことはありません。
とりあえずとっかかりとして、以下が参考になりそうな気がします。方法 : Windows フォームの DataGridView コントロールの行の外観をカスタマイズする
http://msdn2.microsoft.com/ja-jp/library/85kxk29c.aspx -
# 回答じゃまったくないんですが...
数ヶ月すると,
UI に WPF (Windows Presentation Foundation)
というもの(テクノロジ)が使えるようになります。その WPF だと,グリッドのような繰り返し描画は,ListView というもので表現するんですが,
その行は,ListViewItem という形で持つようになり,
ListViewItem は,WPF 内で,ContentControl と呼ばれているもので,
そのListViewItem には,要素を ひとつ 持つことができます。
ふつうは,ViewBase から派生したものが指定されることを想定しているようです。MS からは,ViewBase というものから派生した GridView というものが用意されていて,
それを ListViewItem に指定すると,今の DataGridView のようになるわけです。
見た目は一緒なんですが,仕組み的にはまったく変わります。-------------------------------------------------------
実際には,試していないので保障はできないんですが,
WPF では,各行の内容 表現/描画 は,簡単にやれるんじゃないかと思います。というのは,
WPF では,ContentControl 系のものには,
その中に別のコントロールを入れ子にしていけます。
で,
Canvas という名前のコントロールも ContentControl なんですが,
Canvas という名前から連想できるように,
その中に入れ子で別のコントロールを複数入れることができます。
それも好きな位置に表示させれます。現在は,拡張しようとすると,自力で描画しないといけません。
でも,WPF だと,相当簡単に 宣言的にやれるようになりそうなので,
WPF の研究をした方が近道のような気がします。たぶん。また,データバインディング自体は,ListView 側で行われるので,
その各行の中身の描写は,ViewBase から派生したクラスで利用する
DataTemplate オブジェクトを利用するだけです。
XAMLフォーマット と呼ばれているもので,
描画位置やバインディング等を指定するだけです。
その指定に従って,繰り返し表示をやってくれます。イメージとしては,
How to: Create a Custom View Mode for a ListView
の
<DataTemplate x:Key="centralTile">
<StackPanel Height="100" Width="90">
<Grid Width="70" Height="70" HorizontalAlignment="Center">
<Image Source="{Binding XPath=@Image}" Margin="6,6,6,9"/>
</Grid>
<TextBlock Text="{Binding XPath=@Name}" FontSize="13"
HorizontalAlignment="Center" Margin="0,0,0,1" />
<TextBlock Text="{Binding XPath=@Type}" FontSize="9"
HorizontalAlignment="Center" Margin="0,0,0,1" />
</StackPanel>
</DataTemplate>の箇所です。ここでは,Canvas でなく StackPanel を使っています。
行のイメージが浮かぶと思います。
こんな風に宣言的にやるだけで,描画位置を調整できるので楽だと思います。# Vista で実現されようとしているものですが,
# もちろん,WinXP 上でも使えるテクノロジです。 -
一部 バグが有りましたので 改良しました
Imports System.Windows.Forms
Imports System.Drawing
Public Class ExDataGridView
Inherits DataGridViewPublic Sub New()
MyBase.new()
End Sub
Public pBorderColor As Color = SystemColors.ControlDark
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("境界線のカラー")> _
Public Property BorderColor() As Color
Get
Return pBorderColor
End Get
Set(ByVal value As Color)
pBorderColor = value
End Set
End PropertyPublic pDokCell As New Generic.List(Of Integer)
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("結合するヘッダーを設定する値 設定する値は1列目から2列分、4列目から3列分結合であれば 2,0,0,3というふうに設定 Generic.List型 ")> _
Public Property ドッキングセル() As Generic.List(Of Integer)
Get
Return pDokCell
End Get
Set(ByVal value As Generic.List(Of Integer))
pDokCell = value
End Set
End PropertyPublic pHedTXT() As String
<System.ComponentModel.Category("カスタム")> _
<System.ComponentModel.Description("上部ヘッダーテキストです 1列目から2列分結合した部分のテキストを""A""4列目から3列分結合させた部分のテキストを""B""とする場合 A、空白、空白、B というふうに設定" & _
" 空白に設定している列は元のヘッダーテキストが表示される")> _
Public Property FullHedTxt() As String()
Get
Return pHedTXT
End Get
Set(ByVal value As String())
pHedTXT = value
End Set
End PropertyPrivate Sub Me_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles Me.CellPainting
ヘッダー結合(e, pDokCell)
End SubPublic Function HedTxtSet() As ArrayList
Dim arry As New ArrayList
Dim cel As New ArrayList
Dim col As Integer = Me.ColumnCount - 1
For i As Integer = 0 To col
arry(i) = Me.Columns(i).HeaderText
Next
For Each d As Integer In ドッキングセル
For ii As Integer = d To d + ドッキングセル(d) - 1
arry(d) = FullHedTxt(d)
Next
Next
Return arry
End FunctionPublic Event HedPaint()
Private Sub aaExDataGridView_v6_HedPaint() Handles Me.HedPaint
Dim dok As Integer = 0
For Each d As Integer In ドッキングセル
If d > 1 Then
dok = 1
End If
Next
If dok = 1 Then
Me.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
Me.ColumnHeadersHeight = 34
End If
End SubPrivate Sub ヘッダー結合(ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs, _
ByVal Dokcell As Generic.List(Of Integer))RaiseEvent HedPaint()
If Dokcell Is Nothing Then Exit Sub
If e.ColumnIndex >= 0 AndAlso e.RowIndex = -1 Then
Dim cWid As New Hashtable
Dim ww As Integer
For iii As Integer = 0 To CInt(Dokcell.Count) - 1
ww = 0
If Dokcell(iii) <> Nothing ThenFor id As Integer = iii To iii + Dokcell(iii) - 1
ww = ww + Me.Columns(id).Width
Next
cWid(iii + Dokcell(iii) - 1) = ww
End If
NextDim txt As String = CStr(e.Value)
Dim DokSetMain As New ArrayList
Dim DokSub As New ArrayList
Dim DokTxt As New Hashtable
Dim HedTX As New HashtableDim cc As Integer
For Each d As Integer In Dokcell
If d > 1 Then
Dim int As Integer = cc + d - 1
DokSetMain.Add(int)
DokTxt(int) = Me.Columns(cc).HeaderCell.Value
Dim max As Integer
If Not FullHedTxt Is Nothing Then
max = FullHedTxt.Length
End IfIf cc < max Then
HedTX(int) = FullHedTxt(cc)
End IfIf d > 1 Then
For i As Integer = cc To cc + d - 1
DokSub.Add(i)
Next
End If
End If
cc += 1
Next
Dim col As Integer = e.ColumnIndex
Dim x2 As Integer = e.CellBounds.X
Dim Y2 As Integer = e.CellBounds.Y
Dim hei As Integer = CInt(e.CellBounds.Height / 2)
Dim wid As Integer = e.CellBounds.Width
Dim backBrush As New SolidBrush(e.CellStyle.BackColor)
Dim newRect As New Rectangle(e.CellBounds.X, e.CellBounds.Y, _
e.CellBounds.Width - 1, e.CellBounds.Height - 1)
Dim backColorBrush As New SolidBrush(e.CellStyle.BackColor)
Dim gridBrush As New SolidBrush(Me.GridColor)
Dim gridLinePen As New Pen(gridBrush)
Dim BoPen As New Pen(BorderColor)Dim Bou1 As New Rectangle( _
x2 - 1, _
Y2 + hei, _
wid, _
hei - 1)
Try
'ドッキングセル上段
If DokSetMain.Contains(col) = True Thene.Graphics.FillRectangle(backBrush, e.CellBounds)
Dim Bou2 As New Rectangle(x2 - 1, _
Y2 + hei - 1, _
wid, _
hei)
With e.Graphics
.DrawString(CStr(e.Value), e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + hei + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + hei, x2, Y2 + hei + hei - 1)
.DrawLine(Pens.White, x2, Y2 + hei, x2 + wid - 1, Y2 + hei)End With
txt = HedTX(col)
If txt Is Nothing OrElse txt = "" Then
txt = CStr(DokTxt(col))
End IfDim wid2 As Integer = CInt(cWid(col))
x2 = x2 - (wid2 - wid)Bou1 = New Rectangle(x2 - 1, _
Y2, _
wid2, _
hei - 1)
With e.Graphics
.DrawRectangle(BoPen, Bou1)
.DrawRectangle(BoPen, Bou2)
.DrawString(txt, e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + 1, x2, Y2 + hei - 1)
.DrawLine(Pens.White, x2, Y2 + 1, x2 + wid2 - 1, Y2 + 1)
End With
e.Handled = True
Else
'ドッキングセル以外
If DokSub.Contains(col) = False Then
e.Graphics.FillRectangle(backBrush, e.CellBounds)
Bou1 = New Rectangle(x2 - 1, _
Y2, _
wid, _
hei * 2 - 1)
e.Graphics.DrawRectangle(BoPen, Bou1)
Dim max As Integer = 0
If Not FullHedTxt Is Nothing Then
max = FullHedTxt.Length
End If
Dim txt3 As String = Nothing
If col < max Then
txt3 = FullHedTxt(col)
End If
If Not txt3 Is Nothing AndAlso txt3 <> "" Then
txt = txt3
Else
txt = CStr(e.Value)
End If
With e.Graphics
.DrawString(txt, e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + 1, x2, Y2 + hei * 2 - 1)
.DrawLine(Pens.White, x2, Y2 + 1, x2 + wid - 1, Y2 + 1)
End With
e.Handled = True
Else
'ドッキングセル下段
Bou1 = New Rectangle(x2 - 1, _
Y2 + hei - 1, _
wid, _
hei)
With e.Graphics
.FillRectangle(backBrush, e.CellBounds)
.DrawRectangle(BoPen, Bou1)
.DrawString(CStr(e.Value), e.CellStyle.Font, Brushes.Black, _
x2 + 2, Y2 + hei + 2, _
StringFormat.GenericDefault)
.DrawLine(Pens.White, x2, Y2 + hei, x2, Y2 + hei * 2)
.DrawLine(Pens.White, x2, Y2 + hei, x2 + wid - 1, Y2 + hei)
End With
e.Handled = True
End If
End If
FinallyBoPen.Dispose()
backColorBrush.Dispose()
gridLinePen.Dispose()
gridBrush.Dispose()
backBrush.Dispose()End Try
End IfEnd Sub
End Class
-
かずbooさんのソースを参考に、C#で作成してみました。
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;namespace DataGridViewEx
{
public partial class DataGridViewEx : DataGridView
{
//コンストラクタ
public DataGridViewEx()
{
//セル描画イベントハンドラの追加
this.CellPainting += new DataGridViewCellPaintingEventHandler(DataGridViewEx_CellPainting);
}//ドッキングセルを表す内部クラス
//第0カラムから2カラム分結合し、上段テキストを"A1"とする場合、
//new DataGridViewEx.DockingCell(0, 2, "A1")のようにインスタンスを作成
public class DockingCell
{
//開始セル
private int start;
public int Start
{
get
{
return start;
}
set
{
start = value;
}
}//セル数
private int count;
public int Count
{
get
{
return count;
}
set
{
count = value;
}
}//ヘッダテキスト
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
}
}//コンストラクタ
public DockingCell(int start, int count, string text)
{
this.start = start;
this.count = count;
this.text = text;
}
}//ドッキングセルのリスト
//作成したDockingCell型オブジェクトをAdd()メソッドで追加する
//DockingCellList.Add(new DataGridViewEx.DockingCell(0, 2, "A1"))といった具合
private List<DockingCell> dockingCellList = new List<DockingCell>();
public List<DockingCell> DockingCellList
{
get
{
return dockingCellList;
}
set
{
dockingCellList = value;
}
}//セル描画イベントハンドラ
private void DataGridViewEx_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
//このメソッドでは、ヘッダの描画のみを行う
if (e.ColumnIndex >= 0 && e.RowIndex == -1)
{
//そのヘッダがどのドッキングセルに属しているか調べる
int index = -1;
for (int i = 0; i < DockingCellList.Count; i++)
{
if (e.ColumnIndex >= DockingCellList.Start && e.ColumnIndex < DockingCellList
.Start + DockingCellList
.Count)
{
index = i;
break;
}
}//とりあえず塗りつぶす
e.Graphics.FillRectangle(new SolidBrush(e.CellStyle.BackColor), e.CellBounds);//ドッキングしている場合
if (index >= 0)
{
//上段
int x = e.CellBounds.X;
for (int i = e.ColumnIndex - 1; i >= DockingCellList[index].Start; i--)
{
x -= this.Columns.Width;
}
int width = 0;
for (int i = DockingCellList[index].Start; i < DockingCellList[index].Start + DockingCellList[index].Count; i++)
{
width += this.Columns.Width;
}
Rectangle rect1 = new Rectangle(x, e.CellBounds.Y, width, e.CellBounds.Height / 2);
DrawCell(e.Graphics, rect1);
e.Graphics.DrawString(DockingCellList[index].Text, e.CellStyle.Font, Brushes.Black, rect1.X + 2, rect1.Y + 2);//下段
Rectangle rect2 = new Rectangle(e.CellBounds.X, e.CellBounds.Y + e.CellBounds.Height / 2, e.CellBounds.Width, e.CellBounds.Height / 2);
DrawCell(e.Graphics, rect2);
e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, Brushes.Black, rect2.X + 2, rect2.Y + 2);
}//ドッキングしていない場合
else
{
DrawCell(e.Graphics, e.CellBounds);
e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, Brushes.Black, e.CellBounds.X + 2, e.CellBounds.Y + 2);
}//ハンドルされたことを報告
e.Handled = true;
}
}//セルの描画に用いるメソッド
private void DrawCell(Graphics g, Rectangle rect)
{
g.DrawLine(new Pen(SystemColors.ControlDark), rect.Left - 1, rect.Top, rect.Right - 2, rect.Top);
g.DrawLine(new Pen(SystemColors.ControlDark), rect.Left - 1, rect.Top, rect.Left - 1, rect.Bottom - 1);
g.DrawLine(Pens.White, rect.Left, rect.Top + 1, rect.Right - 2, rect.Top + 1);
g.DrawLine(Pens.White, rect.Left, rect.Top + 1, rect.Left, rect.Bottom - 1);
}
}
} -
窓際族 さんからの引用 datagridview1をexDataGridVIewに変身させることはできませんですよね。
C#でしょうか? C#であればInitializeComponent();という記述がコンストラクタにありますから、そこで右クリックして「定義へ移動」をクリックします。そうするとInitializeComponent()の中に
this.dataGridView1 = new System.Windows.Forms.DataGridView();
という記述が見つかりますから、
this.dataGridView1 = new exDataGridVIew();
とすればdatagridview1がexDataGridVIewに変身します。exDataGridVIewクラスはInitializeComponentから見える位置(スコープ)に記述して下さい。
VBであれば、ドロップダウンよりInitializeComponentを選択して同様に行って下さい。
また、exDataGridVIewをカスタムコントロールにしてしまえば、それをツールボックスに配置し、デザイナで使うことができるようになります。
-
いつもお世話になっております。
ご教示ありがとうございます。
実はちゃっかりクラスに入れて使っています。
this.dataGridView1 = new exDataGridVIew();
こわいけど、やってみます。
色が気に食わないので、
Dim backBrush As New SolidBrush(e.CellStyle.BackColor)
を
Dim backBrush As New SolidBrush(e.CellStyle.BackColor.AliceBlue)
に変更すると、入れ子にしてるから正しく反映されないという警告を受けます。
でも、ちゃんと描画しますが、どうなんでしょう。
正しい、色の変え方はどうするのですか?
-
テストプロジェクトを作ってやってみました。
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.Columns.Add("a1", "Team")
DataGridView1.Columns.Add("a2", "Name")
DataGridView1.Columns.Add("a3", "AB")
DataGridView1.Columns.Add("a4", "BA")
DataGridView1.Columns.Add("a5", "SLG")
DataGridView1.Columns.Add("a6", "OPS")
DataGridView1.Columns.Add("a7", "SO")
DataGridView1.Columns(0).Width = 40
DataGridView1.Columns(1).Width = 40
DataGridView1.Columns(2).Width = 40
DataGridView1.Columns(3).Width = 40
DataGridView1.Columns(4).Width = 40
DataGridView1.Columns(5).Width = 40
DataGridView1.Columns(6).Width = 40
Dim GL As New Generic.List(Of Integer)
GL.Add(2)
GL.Add(0)
GL.Add(0)
GL.Add(2)
DataGridView1.ドッキングセル = GL
Dim text() As String = {" Number One", "", "", " Sluger!"}
DataGridView1.FullHedTxt = text
DataGridView1.Rows.Add()
DataGridView1(0, 0).Value = "SEA"
DataGridView1(1, 0).Value = "Ichiro"
DataGridView1(2, 0).Value = 438
DataGridView1(3, 0).Value = 0.345
DataGridView1(4, 0).Value = 0.543
DataGridView1(5, 0).Value = 0.876
DataGridView1(6, 0).Value = 25
End Subこんなんでちゃんと表示されました。
exdatagridviewはとても有用な資産だと思います。
コンポーネントを変更すれば、機能が増えるだけでまったく問題ありません。
ありがとうございあmす。
-
ご返信ありがとうございます。
回答済マークの付け方がわかりません。どうするのでしょうか。
exDataGridViewは少々変更しました。
単一層のグリッドと入れ換えて使っているので、そのあたりを変更しました。
また、ヘッダーテキストのアラインセンタープロパティも増やしました。
ヘッダーの真ん中に字がかけないと気分が悪いですから。
ただし、横スクロールに対する、文字の再描画が不十分です。
上段の文字だけ消えたままです。下段は大丈夫です。どこが不十分なのか検討してみます。
exDataGridViewはとても気に入りました。常駐クラスにします。
ありがとうございます。