C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: DataGridViewのセル結合がスクロールでおかしくなる


(過去ログ 128 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■76143 / inTopicNo.1)  DataGridViewのセル結合がスクロールでおかしくなる
  
□投稿者/ もん吉 (1回)-(2015/06/03(Wed) 16:27:22)

分類:[.NET 全般] 

Visual Studio Professional 2013 を使用して開発しています。
DataGridViewを初めて使用して苦戦しています。

ヘッダーを非表示にして明細の最初2行をヘッダーとして処理をしています。
1行目を3〜8と9〜14のセルを結合して表題を載せています。

この記述で横スクロールがなければいいのですが、
横スクロールをすると結合セルがずれてしまいます。

スクロールした画面の左からセルの数を数えて処理しているような感じで
結合がかなりおかしくなります。

何とかずれない方法を探してしますが手詰まりです。
どなたか知恵を拝借できないでしょうかよろしくお願いします。

以下のようなソースを書いています。

Private Sub DataGridView_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DataGridView.CellPainting
Dim dv As DataGridView
dv = DataGridView
' 行・列共にヘッダは処理しない
If e.RowIndex < 0 Or e.ColumnIndex < 0 Or e.RowIndex <> 0 Then
Return
End If

Dim rect As Rectangle
Dim cell As DataGridViewCell
Dim MyMax As Integer

rect = e.CellBounds
'結合セルの2列目〜結合の最終列
If (e.ColumnIndex > 3 And e.ColumnIndex <= 8) Or _
(e.ColumnIndex > 9 And e.ColumnIndex <= 14) Then
'描画処理をせずに、イベントハンドラ内で処理を完了したこと通知
e.Handled = True
Else
MyMax = 1
'結合セル最初の列 MyMax=結合セル数-2
If e.ColumnIndex = 3 Then MyMax = 4
If e.ColumnIndex = 9 Then MyMax = 4

'結合セルの長さを計算する
For i As Integer = 0 To MyMax
'右のセルの幅を足す
If e.ColumnIndex + i < dv.Columns.Count Then
cell = DataGridView(e.ColumnIndex + i, e.RowIndex)
rect.Width += cell.Size.Width
End If
Next
rect.X -= 1
rect.Y -= 1
e.Graphics.FillRectangle(New SolidBrush(e.CellStyle.BackColor), rect)
e.Graphics.DrawRectangle(New Pen(dv.GridColor), rect)
TextRenderer.DrawText(e.Graphics, e.FormattedValue.ToString(), e.CellStyle.Font, rect, e.CellStyle.ForeColor, TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter)
e.Handled = True
'End If
End If
End Sub
引用返信 編集キー/
■76149 / inTopicNo.2)  Re[1]: DataGridViewのセル結合がスクロールでおかしくなる
□投稿者/ 魔界の仮面弁士 (371回)-(2015/06/03(Wed) 19:42:14)
No76143 (もん吉 さん) に返信
> ヘッダーを非表示にして明細の最初2行をヘッダーとして処理をしています。
自分はこのような場合、ヘッダー部の高さを増やしておいて、
そこに、複数行分の情報を CellPainting イベントで描画する方法で実装しています。
http://www.vb-user.net/junk/200704031257/DataGridView.png


> スクロールした画面の左からセルの数を数えて処理しているような感じで
基本的には、可視範囲にあるセル群が、左上セルから右下セルに向かって、
「Z」字方向に順次レンダリングされていきます。

ただしスクロール時などは、すべてのセルが再レンダリングされるわけではなく、
スクロールで新たに現れた行に対して、CellPainting が呼ばれます。

たとえば水平スクロールバーを右に動かした場合は、
左側に隠れゆくセルの再描画は発生しませんが、
右側から現れるセルの再描画は必要となります。
左に動かした場合はその逆ですね。



> 結合がかなりおかしくなります。
描画範囲を右方向に伸ばしていくだけではマズイかと。


たとえば、2列目から4列目までを結合する場合、スクロール方向によっては、
2 列目のみが再描画されることもあれば、
4 列目のみが再描画されることもありえます。

そのため 2 列目の CellPainting であれ、4 列目の CellPainting であれ、
「2 列目と 3 列目と 4 列目の範囲」への描画を行うようにします。


テキスト描画のための余白調整などを抜きにして、
列結合のための算出イメージは、こんな感じになるかと思います。(未検証)

 Dim margeLeft = e.CellBounds.Right
 For colIndex = e.ColumnIndex To 0 Step -1
  margeLeft -= grid.Columns(colIndex).Width
  If colIndexが結合列の先端の場合 Then
   Exit For
  End If
 Next
 Dim margeRight = e.CellBounds.Left
 For colIndex = e.ColumnIndex To grid.ColumnCount
  margeRight += grid.Columns(colIndex).Width
  If colIndexが結合列の末尾の場合 Then
   Exit For
  End If
 Next
 Dim cellRect As New Rectangle(margeLeft, e.CellBounds.Top, margeRight - margeLeft, e.CellBounds.Height)



> 以下のようなソースを書いています。
>
> Dim dv As DataGridView
> dv = DataGridView
こういう場合は、
 Dim dv = DirectCast(sender, DataGridView)
の方が良いと思います。

dv だと DataView を連想するので、自分は dgv を使うことが多いですが。


> cell = DataGridView(e.ColumnIndex + i, e.RowIndex)
ここでは dv を使わないのですか?



> '結合セルの2列目〜結合の最終列
> If (e.ColumnIndex > 3 And e.ColumnIndex <= 8) Or _
> (e.ColumnIndex > 9 And e.ColumnIndex <= 14) Then
And / Or ではなく、AndAlso / OrElese を使いましょう。本題とは無関係ですが。



> e.Graphics.FillRectangle(New SolidBrush(e.CellStyle.BackColor), rect)
> e.Graphics.DrawRectangle(New Pen(dv.GridColor), rect)
New で作成したまま引数に渡してはいけません。
ブラシ、ペン、フォントなどといった GDI+ オブジェクトは、IDisposable です。

Using ブロックを使うようにするか、CellPainting を抜ける前に
Dispose メソッドを呼ぶなどして、New したブラシ等を片付けましょう。
引用返信 編集キー/
■76150 / inTopicNo.3)  Re[2]: DataGridViewのセル結合がスクロールでおかしくなる
□投稿者/ 魔界の仮面弁士 (372回)-(2015/06/03(Wed) 20:02:10)
No76149 (魔界の仮面弁士) に追記
>>ヘッダーを非表示にして明細の最初2行をヘッダーとして処理をしています。
> 自分はこのような場合、ヘッダー部の高さを増やしておいて、

うん…? よく見ると、最初の質問コードに、RowIndex 判定のコードが無いですね。
もしかして明細の最初の「2行」ではなく、「2列」の間違いだったのでしょうか。

まぁ、行ヘッダ列であれ、列ヘッダ行であれ、手順的には大差ないので
適宜読み替えてください。

(水平スクロールはドット単位でおこなえますが、
 垂直スクロールはセルの高さ単位で行われるため、
 厳密には同じでは無いですが、やるべきことは変わらないはず)
引用返信 編集キー/
■76168 / inTopicNo.4)  Re[3]: DataGridViewのセル結合がスクロールでおかしくなる
□投稿者/ もん吉 (2回)-(2015/06/05(Fri) 10:36:33)
No76150 (魔界の仮面弁士 さん) に返信

有難う御座います。とても助かりました。
まさか左右のスクロールの方向まで考慮が必要とは思いませんでした。

>見ると、最初の質問コードに、RowIndex 判定のコードが無いですね。
>もしかして明細の最初の「2行」ではなく、「2列」の間違いだったのでしょうか。

最初の2行、上の横並びのヘッダータイトルのつもりなのですが。
判定コードはこれじゃないのでしょうか。

' 行・列共にヘッダは処理しない
If e.RowIndex < 0 OrElse e.ColumnIndex < 0 OrElse e.RowIndex <> 0 Then
Return
End If

魔界の仮面弁士様のサンプルを参考に変更したところヘッダーが固定できました。
以前のように左右のスクロールで罫線が変わることはなくなりました。

もう一つお願いなのですが上2行ヘッダーの1行目と2行目の罫線が出ません。
試行錯誤していますが、よろしければアドバイスをお願いできないでしょうか。

下記コードに変更しました。

Private Sub DataGridView_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DataGridView.CellPainting
Dim dgv As DataGridView
dgv = DataGridView
' 行・列共にヘッダは処理しない
If e.RowIndex < 0 OrElse e.ColumnIndex < 0 OrElse e.RowIndex <> 0 Then
Return
End If

Dim margeLeft = e.CellBounds.Right - 1
Dim colIndex As Integer

For colIndex = e.ColumnIndex To 0 Step -1
margeLeft -= dgv.Columns(colIndex).Width
If colIndex = 3 OrElse colIndex = 9 OrElse colIndex = 15 OrElse colIndex = 21 Then
Exit For
End If
Next
Dim margeRight = e.CellBounds.Left
For colIndex = e.ColumnIndex To dgv.ColumnCount - 1
margeRight += dgv.Columns(colIndex).Width
If colIndex = 8 OrElse colIndex = 14 OrElse colIndex = 20 OrElse colIndex = 24 Then
Exit For
End If
Next
Dim cellRect As New Rectangle(margeLeft, e.CellBounds.Top, margeRight - margeLeft, e.CellBounds.Height)
Dim cellBrush As New SolidBrush(e.CellStyle.BackColor)
Dim cellPen As New Pen(dgv.GridColor)

e.Graphics.FillRectangle(cellBrush, cellRect)
e.Graphics.DrawRectangle(cellPen, cellRect)
TextRenderer.DrawText(e.Graphics, e.FormattedValue.ToString(), e.CellStyle.Font, cellRect, e.CellStyle.ForeColor, TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter)
e.Handled = True

cellBrush.Dispose()
cellPen.Dispose()

End Sub

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -