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

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

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

(補足)Re[3]: DataGridViewのヘッダにチェックボックス


(過去ログ 129 を表示中)

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

■76533 / inTopicNo.1)  DataGridViewのヘッダにチェックボックス
  
□投稿者/ やんまー (5回)-(2015/07/19(Sun) 01:01:48)

分類:[VB.NET/VB2005 以降] 

畏れ入ります。

DataGridViewのヘッダにチェックボックスを表示したくてやってみたのですが、
チェックボックスの背景がどうしても透明になりません。

こちらを参考にさせていただきました。
http://seesaawiki.jp/tame/d/.NET-DataGridView

	Private checkBoxAll As CheckBox = New System.Windows.Forms.CheckBox()
	
	Sub DataGridView1CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs)
		' 列ヘッダーのみ処理を行う。(CheckBox配置列が先頭列の場合)
		If e.ColumnIndex = 0 AndAlso e.RowIndex = -1 Then
			Using bmp As New Bitmap(14,24 )
				' チェックボックスの描画領域を確保
				Dim  g As Graphics = Graphics.FromImage(bmp)
				g.Clear(Color.Transparent)	'・・・(1)
				
				' 描画領域の中央に配置
				Dim pt1 As New Point((bmp.Width - checkBoxAll.Width) / 2, (bmp.Height - checkBoxAll.Height) / 2)
				If pt1.X < 0 Then
					pt1.X = 0
				End If
				If pt1.Y < 0 Then
					pt1.Y = 0
				End If
				
				checkBoxAll.BackColor=Color.Transparent	'・・・(2)
				
				' Bitmapに描画
				checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width, bmp.Height))
				
				' DataGridViewの現在描画中のセルの中央に描画
				Dim x As Integer = (e.CellBounds.Width - bmp.Width) / 2
				Dim y As Integer = (e.CellBounds.Height - bmp.Height) / 2
				
				Dim pt2 As New Point(e.CellBounds.Left + x, e.CellBounds.Top + y)
				
				e.Paint(e.ClipBounds, e.PaintParts)
				e.Graphics.DrawImage(bmp, pt2)
				e.Handled = True
			End Using
		End If
	End Sub



やってみると、こんなふうになってしまいます。
http://gyazo.com/21901d31c43d486f92f359bb7a0a23ea

どうも(1)のclearが全く効いていないような気がします。
試しにBlueにしてみても青くならないからです。

(2)はBlueとすると周りが青くなるので効いていると思います。

どうしたら、参考サイトのように綺麗にチェックボックスを描画できるでしょうか?

よろしくお願い致します。

引用返信 編集キー/
■76535 / inTopicNo.2)  Re[1]: DataGridViewのヘッダにチェックボックス
□投稿者/ 魔界の仮面弁士 (417回)-(2015/07/19(Sun) 13:28:56)
No76533 (やんまー さん) に返信
> どうも(1)のclearが全く効いていないような気がします。
> (2)はBlueとすると周りが青くなるので効いていると思います。

透過という意味で有効なのは、むしろ(1)の方だと思いますよ。


今回の場合、(1)で透明なキャンバスを用意した後で、
> checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width, bmp.Height))
によって、その透明部分をすべて塗りつぶすようにチェックボックスを描画したため、
元の透明部分は失われています。試しに、キャンバスの半分だけ描画させるために、
 g.Clear(Color.Red)
 checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width \ 2, bmp.Height))
としてみれば、状況が分かるかと思います。


一方(2)の方ですが、コントロールの BackColor プロパティに設定する透明度というのは、
コントロールの背景を透過させるという意味ではありません。
「親コントロールの背景」を引き継いで描画するという意味です。


たとえば、Me.PictureBox1.Controls.Add(checkBoxAll) されていれば、
checkBoxAll.BackColor = Color.Transparent の時に DrawToBitmap した背景は、
PictureBox に設定されている背景色・背景画像がそのまま描画されることになりますし、
checkBoxAll.BackColor = Color.FromArgb(128, Color.Blue) であれば、
DrawToBitmap された結果は、そこに半透明の青を重ね塗った色となります。


現在は、CheckBox をどこに配置しているのでしょうか?
もし、どこにも配置していないのだとしたら、既定の色(SystemColors.Control かな?)で
描画されることになると思います。また、Controls.Add していない場合には、念のため、
フォーム終了時にその CheckBox を Dispose しておいた方が良いかもしれません。


> どうしたら、参考サイトのように綺麗にチェックボックスを描画できるでしょうか?
元記事の投稿者である mecha_dog さんがどうしていたのかは分かりませんが、
たとえば checkBoxAll のチェックボックスに対して、
 (案1) AutoSize を使わずに、かつ、背景部が必要ないようなサイズで配置しておく
 (案2) 親コントロールの背景に、実際のヘッダー部に相当する背景をセットしておく
などでは無いでしょうか。


あるいは描画に拘らないなら、CheckBox を DataGridView の座標に重ねて配置するという手もあります。
この場合、CheckBox そのものが配置されるため、マウスホバー時の状態や
クリック時の表現も維持されるという利点があります。

とはいえ、列幅変更や水平スクロールが必要となると、そのための位置調整が必要なので、
その場合はむしろ、描画の方が都合が良いかもしれません。
描画の際の余白部分が問題になるようであれば、描画用のダミー CheckBox に対して
DrawToBitmap を呼び出すのではなく、CheckBoxRenderer.DrawCheckBox または
VisualStyleRenderer.DrawBackground を使って描画してみては如何でしょうか。

http://dobon.net/vb/dotnet/graphics/drawvisualcontrol.html



'先頭列のヘッダー部に対して描画処理
If e.ColumnIndex = 0 AndAlso e.RowIndex = -1 Then
  '実際には、マウス位置やチェック状態に応じて state 値を変更する
  Dim state As VisualStyles.CheckBoxState = VisualStyles.CheckBoxState.UncheckedNormal

  '左上では都合が悪ければ、適宜調整を
  Dim pos = e.CellBounds.Location

  '標準の描画処理
  e.Paint(e.ClipBounds, e.PaintParts)

  'その上にチェックボックスを重ね描き
  CheckBoxRenderer.DrawCheckBox(e.Graphics, pos, state)

  e.Handled = True
End If
引用返信 編集キー/
■76536 / inTopicNo.3)  Re[2]: DataGridViewのヘッダにチェックボックス
□投稿者/ やんまー (7回)-(2015/07/20(Mon) 01:35:34)
魔界の仮面弁士 様

ご丁寧にありがとうございます。

> checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width \ 2, bmp.Height))
> としてみれば、状況が分かるかと思います。

やってみました。わかりました!


> 現在は、CheckBox をどこに配置しているのでしょうか?

宣言しているだけで、どこにも配置していません。


> (案1) AutoSize を使わずに、かつ、背景部が必要ないようなサイズで配置しておく

checkBoxAll.AutoSize=False
checkBoxAll.Width=14
checkBoxAll.Height=14

としてみましたところ、バッチリでした!

なるほど、AutoSizeがいたずらしていたというわけですね・・・


後半のサンプルコードも試させていただきました。
これだとクリックしてもそのままでは反応がないのですね・・・。

先の方法でうまくいきそうですので、こちらで何とかやってみます!


ありがとうございました!!!










No76535 (魔界の仮面弁士 さん) に返信
> ■No76533 (やんまー さん) に返信
>>どうも(1)のclearが全く効いていないような気がします。
>>(2)はBlueとすると周りが青くなるので効いていると思います。
>
> 透過という意味で有効なのは、むしろ(1)の方だと思いますよ。
>
>
> 今回の場合、(1)で透明なキャンバスを用意した後で、
>>checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width, bmp.Height))
> によって、その透明部分をすべて塗りつぶすようにチェックボックスを描画したため、
> 元の透明部分は失われています。試しに、キャンバスの半分だけ描画させるために、
>  g.Clear(Color.Red)
>  checkBoxAll.DrawToBitmap(bmp, New Rectangle(pt1.X, pt1.Y, bmp.Width \ 2, bmp.Height))
> としてみれば、状況が分かるかと思います。
>
>
> 一方(2)の方ですが、コントロールの BackColor プロパティに設定する透明度というのは、
> コントロールの背景を透過させるという意味ではありません。
> 「親コントロールの背景」を引き継いで描画するという意味です。
>
>
> たとえば、Me.PictureBox1.Controls.Add(checkBoxAll) されていれば、
> checkBoxAll.BackColor = Color.Transparent の時に DrawToBitmap した背景は、
> PictureBox に設定されている背景色・背景画像がそのまま描画されることになりますし、
> checkBoxAll.BackColor = Color.FromArgb(128, Color.Blue) であれば、
> DrawToBitmap された結果は、そこに半透明の青を重ね塗った色となります。
>
>
> 現在は、CheckBox をどこに配置しているのでしょうか?
> もし、どこにも配置していないのだとしたら、既定の色(SystemColors.Control かな?)で
> 描画されることになると思います。また、Controls.Add していない場合には、念のため、
> フォーム終了時にその CheckBox を Dispose しておいた方が良いかもしれません。
>
>
>>どうしたら、参考サイトのように綺麗にチェックボックスを描画できるでしょうか?
> 元記事の投稿者である mecha_dog さんがどうしていたのかは分かりませんが、
> たとえば checkBoxAll のチェックボックスに対して、
>  (案1) AutoSize を使わずに、かつ、背景部が必要ないようなサイズで配置しておく
>  (案2) 親コントロールの背景に、実際のヘッダー部に相当する背景をセットしておく
> などでは無いでしょうか。
>
>
> あるいは描画に拘らないなら、CheckBox を DataGridView の座標に重ねて配置するという手もあります。
> この場合、CheckBox そのものが配置されるため、マウスホバー時の状態や
> クリック時の表現も維持されるという利点があります。
>
> とはいえ、列幅変更や水平スクロールが必要となると、そのための位置調整が必要なので、
> その場合はむしろ、描画の方が都合が良いかもしれません。
> 描画の際の余白部分が問題になるようであれば、描画用のダミー CheckBox に対して
> DrawToBitmap を呼び出すのではなく、CheckBoxRenderer.DrawCheckBox または
> VisualStyleRenderer.DrawBackground を使って描画してみては如何でしょうか。
>
> http://dobon.net/vb/dotnet/graphics/drawvisualcontrol.html
>
>
>
> '先頭列のヘッダー部に対して描画処理
> If e.ColumnIndex = 0 AndAlso e.RowIndex = -1 Then
>   '実際には、マウス位置やチェック状態に応じて state 値を変更する
>   Dim state As VisualStyles.CheckBoxState = VisualStyles.CheckBoxState.UncheckedNormal
>
>   '左上では都合が悪ければ、適宜調整を
>   Dim pos = e.CellBounds.Location
>
>   '標準の描画処理
>   e.Paint(e.ClipBounds, e.PaintParts)
>
>   'その上にチェックボックスを重ね描き
>   CheckBoxRenderer.DrawCheckBox(e.Graphics, pos, state)
>
>   e.Handled = True
> End If
解決済み
引用返信 編集キー/
■76537 / inTopicNo.4)  (補足)Re[3]: DataGridViewのヘッダにチェックボックス
□投稿者/ 魔界の仮面弁士 (418回)-(2015/07/20(Mon) 11:42:14)
No76536 (やんまー さん) に返信
> checkBoxAll.Width=14
> checkBoxAll.Height=14
CheckBox のボックス有効域のサイズは環境によって異なりますので、
14x14 が適切とは限りません。正しいサイズを実行時に測定する場合には、
CheckBoxRenderer.GetGlyphSize メソッドを使うことができます。


> 後半のサンプルコードも試させていただきました。
> これだとクリックしてもそのままでは反応がないのですね・・・。

No76533 でご紹介頂いた mecha_dog さんのコードでは、
列ヘッダー部のクリック時に、ヘッダー部のチェックボックスの状態を
 checkBoxAll.Checked = !checkBoxAll.Checked;  // [C#]
 checkBoxAll.Checked = Not checkBoxAll.Checked ' VB
のようにして、自身で変更されていましたよね。


第二案として挙げた No76535 のコードではcheckBoxAll を使用していませんが、
手順としては上記と同様で、ヘッダー部がクリックされた際に、そこに描画した
ヘッダー部のチェックボックスの状態を切り替える作業が必要になります。
具体的には、先のコードの
 '実際には、マウス位置やチェック状態に応じて state 値を変更する
 Dim state As VisualStyles.CheckBoxState = VisualStyles.CheckBoxState.UncheckedNormal
の変数が示す状態値を、CheckedPressed 等に差し替えるということです。
https://msdn.microsoft.com/ja-jp/library/System.Windows.Forms.VisualStyles.VisualStyleElement.Button.CheckBox_properties.aspx

ついでに、InvalidateCell メソッドで再描画処理を促す必要もあるかも。



>> 現在は、CheckBox をどこに配置しているのでしょうか?
> 宣言しているだけで、どこにも配置していません。

繰り返しにはなりますが、Control は IDisposable です。
Controls.Add している場合は、Form の Dispose 時に一緒に Dispose されますが、
Controls.Add していないものは、開発者が使用後に Dispose するのが望ましいです。
http://dobon.net/vb/bbs/log3-43/26056.html


なお、フォームの Dispose 前に自分で Controls.RemoveAt や Clear を呼び出した場合、
そこにあったコントロールの Dispose は、自前で行う必要があります。
動的なコントロールの生成・削除を行う場合には注意が必要ですね。

[Controls.Clear メソッド]
https://msdn.microsoft.com/ja-jp/library/system.windows.forms.control.controlcollection.clear.aspx
》 Clear メソッドを呼び出しても、コントロールのハンドルがメモリから削除されることはありません。
》 メモリ リークを防ぐには、Dispose メソッドを明示的に呼び出す必要があります。
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -