none
DataGridViewの行ヘッダーの左余白 RRS feed

  • 質問

  • DataGridViewの行ヘッダーの左余白をなくしたいのですが可能でしょうか。

    と言うのも、現在行を示す三角印を非表示にしたくて、こちらを参考に解決したのですが、
     http://social.msdn.microsoft.com/Forums/ja-JP/f808334d-1cd0-42c5-83ae-c455c10e3ba9/datagridview?forum=vbexpressja
     Paintメソッドのオーバーライド
    行ヘッダーに文字を表示してみると、少し右に寄って表示されています。
    三角印を表示した場合と同じ位置に表示される事から、三角印分の余白があるのではないかと想像しています。

    この余白をなくして、左端に寄せて行ヘッダーの文字を表示したいと思っています。

    Paintメソッドのオーバーライドで cellStyle の Padding でどうにかなるかと思い試してみたところ、
    これは三角印を含めてその周囲の余白のようで、これでは左に寄せそうもありませんでした。

    加えて、行ヘッダーの背景の左端が少し薄くなっているのですが、
    この部分をなくして背景色一色にしたいと思っています。

    いずれかでも、ご存知の方がいらしたら、教えてください。
    2014年6月9日 11:44

すべての返信

  • こんな

    Public Class Form1
        Dim DataGridView1 As DataGridView
        Sub New()
    
            ' この呼び出しはデザイナーで必要です。
            InitializeComponent()
    
            ' InitializeComponent() 呼び出しの後で初期化を追加します。
            Me.DataGridView1 = New DataGridView
            Me.DataGridView1.Dock = DockStyle.Fill
            Me.DataGridView1.Columns.Add("Column1", "Column1")
            Me.DataGridView1.Columns.Add("Column2", "Column2")
    
            Me.DataGridView1.RowTemplate.HeaderCell = New myDataGridViewRowHeaderCell()
    
            For i As Integer = 0 To 99
                Me.DataGridView1.Rows.Add()
            Next
    
            Me.Controls.Add(Me.DataGridView1)
        End Sub
    End Class
    
    Public Class myDataGridViewRowHeaderCell
        Inherits DataGridViewRowHeaderCell
    
        Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, cellState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
    
            If (paintParts And DataGridViewPaintParts.Background) = DataGridViewPaintParts.Background Then
                'まず描画する範囲を左にずらした偽の領域を作る
                '適当に20ずらしてみる
                Dim cellBounds_LeftShift As Rectangle = New Rectangle(cellBounds.X - 20, cellBounds.Y, cellBounds.Width + 20, cellBounds.Height)
    
                '左にずれた領域に対して背景のみを描画させることで左端の白色部分を範囲外にしてしまう
                MyBase.Paint _
                    (graphics _
                     , clipBounds _
                     , cellBounds_LeftShift _
                     , rowIndex _
                     , cellState _
                     , value _
                     , formattedValue _
                     , errorText _
                     , cellStyle _
                     , advancedBorderStyle _
                     , DataGridViewPaintParts.Background)
            End If
    
            '背景とコンテンツ(三角)以外で上書き
            '背景はすでに描画済みなので枠線とかのみが描画される。
            MyBase.Paint _
                (graphics _
                 , clipBounds _
                 , cellBounds _
                 , rowIndex _
                 , cellState _
                 , value _
                 , formattedValue _
                 , errorText _
                 , cellStyle _
                 , advancedBorderStyle _
                 , paintParts And Not (DataGridViewPaintParts.ContentBackground Or DataGridViewPaintParts.Background))
    
    
            Dim textBrush As Brush
            textBrush = SystemBrushes.ControlText
    
            formattedValue = rowIndex 'お試し
    
            If (formattedValue IsNot Nothing) Then
                Dim p As Point
                p = cellBounds.Location
    
                Dim height As Single = cellStyle.Font.GetHeight()
                p = New Point(p.X, p.Y + (cellBounds.Height - height) / 2) '縦のセンターに配置するための位置計算
    
                graphics.DrawString(formattedValue.ToString(), cellStyle.Font, textBrush, p)'自分で文字を描画する
            End If
        End Sub
    
    End Class
    行ヘッダーの左端が白いのは、例えばWindowsのテーマ設定をクラシックにしたりするとこの左端の白い部分はありません。
    この方法で左端を消した場合、将来テーマが変更された時におかしくなる可能性はあります。
    それがまずい場合は自分でBrushを作ってFillRectangleで塗りつぶしを行ってください。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2014年6月9日 13:42
  • 返信いただき、ありがとうございます。

    とても参考になりました。
    そのまま使えそうなくらいです。

    行ヘッダーには、

     Me.DataGridView1.Rows(0).HeaderCell.Value = "文字"

    のような感じで表示したい文字を設定しようとしていたので、

     formattedValue = value

    として、セルの値を設定してみました。
    そのままだと、セルの値と重なって表示されてしまうので、

     , paintParts And Not (DataGridViewPaintParts.ContentBackground Or DataGridViewPaintParts.Background Or DataGridViewPaintParts.ContentForeground))

    として ContentForeground を追加する事でセルの値を非表示にして重なりを回避してみましたが、
    それでよかったでしょうか。
    他によりよい方法があれば教えてください。

    それと、縦のセンターに配置まで配慮してくださってありがとうございます。

    元の質問では左寄せしか書かなかったのですが、実は右寄せや中央寄せも必要で、
    その時は cellStyle.Alignment で簡単にできていたものですからあえて書きませんでした。
    今回の方法でセルの値は非表示にしたため、右寄せや中央寄せの座標を計算する必要があると思います。
    cellStyle.Font.GetHeight() をまねて、cellStyle.Font.GetWidth() があればと思ったのですが、
    横幅はフォントと文字内容によって変動するためかスタイルの情報にはなさそうで詰まってしまいました。

    追加の質問になってすみませんが、右寄せや中央寄せに関するヒントでもあれば教えてください。
    2014年6月10日 1:34
  • として ContentForeground を追加する事でセルの値を非表示にして重なりを回避してみましたが、
    それでよかったでしょうか。

    それでいいですよ。

    追加の質問になってすみませんが、右寄せや中央寄せに関するヒントでもあれば教えてください。

    Graphics.MeasureStringで文字列の大きさが得られます。

    Public Class myDataGridViewRowHeaderCell
        Inherits DataGridViewRowHeaderCell
    
        Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, cellState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
    
            If (paintParts And DataGridViewPaintParts.Background) = DataGridViewPaintParts.Background Then
                'まず描画する範囲を左にずらした偽の領域を作る
                '適当に20ずらしてみる
                Dim cellBounds_LeftShift As Rectangle = New Rectangle(cellBounds.X - 20, cellBounds.Y, cellBounds.Width + 20, cellBounds.Height)
    
                '左にずれた領域に対して背景のみを描画させることで左端の白色部分を範囲外にしてしまう
                MyBase.Paint _
                    (graphics _
                     , clipBounds _
                     , cellBounds_LeftShift _
                     , rowIndex _
                     , cellState _
                     , value _
                     , formattedValue _
                     , errorText _
                     , cellStyle _
                     , advancedBorderStyle _
                     , DataGridViewPaintParts.Background)
            End If
    
            '背景とコンテンツ(三角)以外で上書き
            '背景はすでに描画済みなので枠線とかのみが描画される。
            MyBase.Paint _
                (graphics _
                 , clipBounds _
                 , cellBounds _
                 , rowIndex _
                 , cellState _
                 , value _
                 , formattedValue _
                 , errorText _
                 , cellStyle _
                 , advancedBorderStyle _
                 , paintParts And Not (DataGridViewPaintParts.ContentBackground Or DataGridViewPaintParts.Background Or DataGridViewPaintParts.ContentForeground))
    
    
            Dim textBrush As Brush
            textBrush = SystemBrushes.ControlText
    
            formattedValue = rowIndex 'お試し
    
            If (formattedValue IsNot Nothing) Then
                Dim text As String
    
                text = formattedValue
    
                Dim size As SizeF = graphics.MeasureString(text, cellStyle.Font)
    
                Dim p As Point
                p = cellBounds.Location
    
                '水平方向のみを取り出す
                Dim horizontal As DataGridViewContentAlignment = cellStyle.Alignment And (DataGridViewContentAlignment.TopLeft _
                                                                                          Or DataGridViewContentAlignment.TopCenter _
                                                                                          Or DataGridViewContentAlignment.TopRight)
                Select Case (horizontal)
                    Case DataGridViewContentAlignment.TopLeft
                        p.X = p.X
                    Case DataGridViewContentAlignment.TopCenter
                        p.X = cellBounds.Left + (cellBounds.Width - size.Width) / 2
                    Case DataGridViewContentAlignment.TopRight
                        p.X = cellBounds.Right - size.Width
                    Case Else
                End Select
    
                '垂直方向のみ取り出す
                Dim vertical As DataGridViewContentAlignment = cellStyle.Alignment And (DataGridViewContentAlignment.TopLeft _
                                                                                        Or DataGridViewContentAlignment.MiddleLeft _
                                                                                        Or DataGridViewContentAlignment.BottomLeft )
                Select Case (vertical)
                    Case DataGridViewContentAlignment.TopLeft
                        p.Y = p.Y
                    Case DataGridViewContentAlignment.MiddleLeft
                        p.Y = p.Y + (cellBounds.Height - size.Height) / 2
                    Case DataGridViewContentAlignment.BottomLeft
                        p.Y = cellBounds.Bottom - size.Height
                    Case Else
                End Select
    
                graphics.DrawString(formattedValue.ToString(), cellStyle.Font, textBrush, p) '自分で文字を描画する
            End If
        End Sub
    
    End Class


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)



    2014年6月10日 3:52
  • 個人的にはレコードセレクタを出さなくする処理はDataGridViewRowHeaderCellをベースとした派生クラスで行い、
    文字描画はRowPostPaintイベントでやる方法が好きなので参考まで。
    ※Form1上にDataGridView1を置いただけのクラスに対するソースです。

    Imports System.Windows.Forms
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            DataGridView1.RowTemplate.HeaderCell = New NoTriangleDataGridViewRowHeaderCell()
            DataGridView1.DataSource = CreateDataTable()
            DataGridView1.RowHeadersWidth = 100
    
        End Sub
    
        Private Function CreateDataTable() As DataTable
            Dim table As New DataTable("TABLE")
            table.Columns.Add("ID", Type.GetType("System.Int32"))
            table.Columns.Add("NAME", Type.GetType("System.String"))
    
            For index = 1 To 10
                Dim row As DataRow = table.NewRow
                row("ID") = index
                row("NAME") = "名称" + index.ToString()
                table.Rows.Add(row)
            Next
            table.AcceptChanges()
            Return table
        End Function
    
        Private Sub DataGridView1_RowPostPaint(sender As System.Object, e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles DataGridView1.RowPostPaint
            Dim grid As DataGridView = DirectCast(sender, DataGridView)
            '描画範囲
            Dim rect As New Rectangle(e.RowBounds.Left, e.RowBounds.Top, grid.RowHeadersWidth, e.RowBounds.Height)
            rect.Inflate(-2, -2)
            If Not grid(1, e.RowIndex).Value Is Nothing Then
                Dim align As TextFormatFlags = TextFormatFlags.Left
                '描画する
                TextRenderer.DrawText(e.Graphics, grid(1, e.RowIndex).Value.ToString() _
                 , e.InheritedRowStyle.Font, rect, e.InheritedRowStyle.ForeColor _
                 , align + TextFormatFlags.VerticalCenter)
            End If
        End Sub
    End Class
    
    Public Class NoTriangleDataGridViewRowHeaderCell
        Inherits DataGridViewRowHeaderCell
    
        Protected Overrides Sub Paint(graphics As System.Drawing.Graphics, clipBounds As System.Drawing.Rectangle, cellBounds As System.Drawing.Rectangle, rowIndex As Integer, cellState As System.Windows.Forms.DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As System.Windows.Forms.DataGridViewCellStyle, advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, paintParts As System.Windows.Forms.DataGridViewPaintParts)
    
            paintParts = paintParts And Not DataGridViewPaintParts.ContentBackground
            MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
    
        End Sub
    End Class
    
    ※複数クラスが一緒にいるのは適宜分割して下さい。
    2014年6月10日 10:28
  • 再度の返信、ありがとうございます。

    Graphics.MeasureString で幅などが調べられるのですね。
    勉強になりました。
    今回の DataGridView とは関係ありませんが、
    これから印刷処理をやっていく上でも必要になりそうな気がしています。

    水平方向/垂直方向の取り出し演算がなぜかうまくいかなかったので、
    Select Case の方でそれぞれを判断するようにしました。

    おかげさまで期待通りにできました。
    感謝します。
    2014年6月10日 10:36
  • dell_precisionさん、解決したようで良かったですね。

    よろしければ、解決の参考になった回答があれば、「回答としてマーク」をしていただければ喜びます。「回答としてマーク」することにより、後に検索した人が回答を見つけやすくなりますし、回答者も励みになると思います。
    よろしくお願いいたします。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2014年6月11日 0:33
    モデレータ
  • 昨日の私の投稿同時刻に新たな返信をいただいていたのに気づかず、
    いましがた内容を確認させていただきました。

    同じ動作(あくまで見た目には)をするにも、
    色々な手法やコーディングがあるのですね。

    好みで言うと、
    処理が二分されてしまうのはあまり好きではないのですが、
    文字寄せの処理が簡単なのが好きなところです。

    全体的な処理は gekkaさんからの Paint のみでの処理とし、
    文字描画を aviator__さんからの TextRenderer.DrawText で試したところ、
    多分、大丈夫じゃないかなと思っています。
    いいところどりですっきりしたソースになりました。

    完成してしまうと、後から見る事もあまりないのですが、
    実際の処理は異なる点が色々あると思うので、
    パフォーマンスが重要な際には見直してみようと思います。

    おふた方ともに、ありがとうございました。

    2014年6月11日 4:36