DataGridViewのボタンにアイコンを付ける

  • 2014.05.22 Thursday
  • 12:16

DataGridViewにボタンを付ける場合は、
例えば、いつもお世話になっているDOBON.NETのページのような感じで追加すれば、

DataGridViewの列にボタンを表示する

こんな感じでボタン(右列)を付けられる
DataGridView ボタン アイコン


しかしこのボタンはTextは表示できても、普通のButtonのようにイメージを貼り付けたりはできない。

ボタンにイメージは貼り付けられないのか?という質問があったので、
ネットで調べてみると、やっぱりというのか、DataGridViewButtonColumnをホスト(継承)して作るほかなさそうである。

DataGridView Image Button Cell
DataGridViewにMaskedTextBoxを表示する
DataGridViewにProgressBarを表示する
Windows フォーム DataGridView Cells でコントロールをホストする

あとは、ListViewを使ってみるとか・・・

ListViewにボタンを追加するには?

で、ホストするソースがあまりに長いので(しかも自分は今のところ使わない機能だし)、
挫けた私はDataGridViewを改造して作ってみた。
 
‌ 
Public Class DataGridViewButton
    Inherits DataGridView
‌ 
#Region "定義"
‌ 
    Private Enum ButtonImageDefine
‌ 
        ''' <summary>通常</summary>
        [Default] = 0
        ''' <summary>通過</summary>
        Hover = 1
        ''' <summary>押した</summary>
        Push = 2
‌ 
    End Enum
‌ 
#End Region
‌ 
#Region "変数"
‌ 
    ''' <summary>ボタンイメージのカラム</summary>
    Private _ButtonImageColumnIndex As Int32 = 4I
‌ 
    ''' <summary>通常</summary>
    Private _DefaultImage As Bitmap = Nothing
    ''' <summary>通過</summary>
    Private _HoverImage As Bitmap = Nothing
    ''' <summary>押した</summary>
    Private _PushImage As Bitmap = Nothing
‌ 
    ''' <summary>押した</summary>
    Private _ButtonClicked As Boolean = False
    ''' <summary>ボタンの状態</summary>
    Private _CurrentStatus As ButtonImageDefine = ButtonImageDefine.Default
‌ 
#End Region
‌ 
#Region "設定"
‌ 
    ''' <summary>通常ボタン設定</summary>
    Public Sub SetDefaultButtonImage(ByVal SourceImage As Bitmap)
‌ 
        Call SetButtonImage(SourceImage, _DefaultImage)
‌ 
    End Sub
‌ 
    ''' <summary>通過ボタン設定</summary>
    Public Sub SetHoverButtonImage(ByVal SourceImage As Bitmap)
‌ 
        Call SetButtonImage(SourceImage, _HoverImage)
‌ 
    End Sub
‌ 
    ''' <summary>押したボタン設定</summary>
    Public Sub SetPushButtonImage(ByVal SourceImage As Bitmap)
‌ 
        Call SetButtonImage(SourceImage, _PushImage)
‌ 
    End Sub
‌ 
    ''' <summary>ボタン設定</summary>
    Private Sub SetButtonImage(ByVal SourceImage As Bitmap, ByRef SetButtonImage As Bitmap)
‌ 
        Dim gImg As Graphics
‌ 
        ''既に設定されている場合は先にDisposeした方がいいかも
        'If SetButtonImage IsNot Nothing Then
        '    Call SetButtonImage.Dispose()
        '    SetButtonImage = Nothing
        'End If
‌ 
        SetButtonImage = New Bitmap(SourceImage.Width, SourceImage.Height) '新規作成
        gImg = Graphics.FromImage(SetButtonImage)
‌ 
        Call gImg.DrawImage(SourceImage, 0I, 0I) '描画
        Call gImg.Dispose()
        gImg = Nothing
‌ 
    End Sub
‌ 
    'フォーム終了時に破棄するような関数を作っておいた方がよいかも
‌ 
#End Region
‌ 
#Region "イベント"
‌ 
    ''' <summary>ボタンクリック時のイベント</summary>
    Public Event URLButtonClick(ByVal sender As ObjectByVal url As String)
    'Public Event URLButtonClick(ByVal sender As Object, ByVal SourceIndex As Int32)
‌ 
#End Region
‌ 
#Region "マウスイベント"
‌ 
    ''' <summary>ボタンダウン</summary>
    Protected Overrides Sub OnCellMouseDown(ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs)
‌ 
        If e.ColumnIndex = _ButtonImageColumnIndex AndAlso e.Button = Windows.Forms.MouseButtons.Left Then '対象カラムで左クリック
‌ 
            Call ButtonImageChange(e.RowIndex, ButtonImageDefine.Push)
            _ButtonClicked = True 'マウスをクリックした
‌ 
        Else
            Call ButtonImageDefult(e.RowIndex) 'リセット
        End If
‌ 
        Call MyBase.OnCellMouseDown(e)
‌ 
    End Sub
‌ 
    ''' <summary>ボタンアップ</summary>
    Protected Overrides Sub OnCellMouseUp(ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs)
‌ 
        If e.ColumnIndex = _ButtonImageColumnIndex AndAlso e.Button = Windows.Forms.MouseButtons.Left Then '対象カラムで左クリック
            If _ButtonClicked = True Then 'クリックしている状態
‌ 
                Dim dTable As DataTable = DirectCast(Me.DataSource, DataTable)
                Dim rItem() As Object = dTable.Rows(e.RowIndex).ItemArray 'ソートしていたらDefultViewから取得しないと取得位置がずれる場合があるよ
                Dim uItem As String = CStr(rItem(5I)) '隠し列とかに実際に使う引数を入れておくなど
‌ 
                RaiseEvent URLButtonClick(Me, uItem) 'イベントに送る
                'RaiseEvent URLButtonClick(Me, e.RowIndex) 'または行番号やキーワードを送って対象の配列から取得でもよい
‌ 
                rItem = Nothing
                dTable = Nothing
            End If
        End If
‌ 
        Call ButtonImageDefult(e.RowIndex) 'リセット
        Call MyBase.OnCellMouseUp(e)
‌ 
    End Sub
‌ 
    ''' <summary>マウスが離れた</summary>
    Protected Overrides Sub OnCellMouseLeave(ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
‌ 
        Call ButtonImageDefult(e.RowIndex) 'リセット
        Call MyBase.OnCellMouseLeave(e)
‌ 
    End Sub
‌ 
    ''' <summary>マウスが通過している</summary>
    Protected Overrides Sub OnCellMouseEnter(ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
‌ 
        If e.ColumnIndex = _ButtonImageColumnIndex Then
            Call ButtonImageChange(e.RowIndex, ButtonImageDefine.Hover)
        Else
            Call ButtonImageDefult(e.RowIndex) 'リセット
        End If
‌ 
        Call MyBase.OnCellMouseEnter(e)
‌ 
    End Sub
‌ 
    ''' <summary>デフォルトに戻す</summary>
    Private Sub ButtonImageDefult(ByVal RowIndex As Int32)
        _ButtonClicked = False '仮に対象セルから離れた場合でもここでリセットすればドラッグ状態でもリセットできるはず
        Call ButtonImageChange(RowIndex, ButtonImageDefine.Default) 'リセット
    End Sub
‌ 
    ''' <summary>アイコンを変更する</summary>
    Private Sub ButtonImageChange(ByVal RowIndex As Int32, ByVal ChangeImageType As ButtonImageDefine)
        'Private Sub ButtonImageDefult(ByVal ColumnIndex As Int32, ByVal RowIndex As Int32)
‌ 
        If RowIndex < 0Then '行がない
            Exit Sub
        End If
‌ 
        If _CurrentStatus = ChangeImageType Then 'イメージが同じ(ちらつき防止)
            Exit Sub
        End If
‌ 
        Dim dTable As DataTable = DirectCast(Me.DataSource, DataTable)
        Dim rItem() As Object = dTable.Rows(RowIndex).ItemArray 'ソートしていたらDefultViewから取得しないと取得位置がずれる場合があるよ
‌ 
        Dim bImg As Bitmap
        Dim gImg As Graphics
‌ 
        '   'リークするかもしれないからあらかじめDisposeした方がいいかも
        '   If IsDBNull(rItem(_ButtonImageColumnIndex)) = False _
        'AndAlso TypeOf rItem(_ButtonImageColumnIndex) Is Bitmap Then
        '       If rItem(_ButtonImageColumnIndex) IsNot Nothing Then
        '           Call DirectCast(rItem(_ButtonImageColumnIndex), Bitmap).Dispose() '破棄
        '           rItem(_ButtonImageColumnIndex) = Nothing
        '       End If
        '   End If
‌ 
        If ChangeImageType = ButtonImageDefine.Hover Then
            _CurrentStatus = ButtonImageDefine.Hover
            bImg = New Bitmap(_HoverImage.Width, _HoverImage.Height)
            gImg = Graphics.FromImage(bImg)
            Call gImg.DrawImage(_HoverImage, 0I, 0I)
        ElseIf ChangeImageType = ButtonImageDefine.Push Then
            _CurrentStatus = ButtonImageDefine.Push
            bImg = New Bitmap(_PushImage.Width, _PushImage.Height)
            gImg = Graphics.FromImage(bImg)
            Call gImg.DrawImage(_PushImage, 0I, 0I)
        Else
            _CurrentStatus = ButtonImageDefine.Default
            bImg = New Bitmap(_DefaultImage.Width, _DefaultImage.Height)
            gImg = Graphics.FromImage(bImg)
            Call gImg.DrawImage(_DefaultImage, 0I, 0I)
        End If
‌ 
        Call gImg.Dispose()
        gImg = Nothing
‌ 
        rItem(_ButtonImageColumnIndex) = bImg
        bImg = Nothing
‌ 
        dTable.Rows(RowIndex).ItemArray = rItem '戻さないと反映されないみたい
‌ 
        rItem = Nothing
        dTable = Nothing
‌ 
    End Sub
‌ 
#End Region
‌ 
End Class


まず、上の改造DataGridViewの4列目がボタンということにして動作するようにしているので、
4列目にDataGridViewImageColumnを設定する必要がある

DataGridView ボタン アイコン

このイメージをマウスの動作によって変更するような仕掛けになっている。

イメージは適当なものを用意して、FormがLoadしたときに読み込むなどをすれば良い
 
Call Me.DataGridViewButton1.SetDefaultButtonImage(MyDefaultButtonImage)
Call Me.DataGridViewButton1.SetHoverButtonImage(MyHoverButtonImage)
Call Me.DataGridViewButton1.SetPushButtonImage(MyPushButtonImage)

マウスがクリックした場合のイベントは、クリックしたときの何をするのかということになるが、
例えば上の例ではURLを非表示の5列目から読み取ってイベントを発生させるようにしている。

フォーム側でそのイベントを取って、何か作業をさせればよい
 
Private Sub DataGridViewButton1_URLButtonClick(ByVal sender As ObjectByVal url As StringHandles DataGridViewButton1.URLButtonClick
    Try
        Call Process.Start(url)
    Catch ex As Exception
    End Try
End Sub


さて、試しに適当なデータを入れて動作させてみると
(上の例の場合は、データはDataTableを作ってDataSourceへ入れている)

マウスがボタンに触れていない状態
DataGridView ボタン アイコン

マウスが触れた状態
DataGridView ボタン アイコン

マウスがクリックされた状態
DataGridView ボタン アイコン


まぁそれなりに動いているようだ

ちなみに、画像をころころと切り替えたりしているので、
破棄するところはちゃんと管理しておかないとメモリーリークの原因となるので注意が必要である。


関連投稿
DataGridView と DataTable と Combobox(コンボボックス)
DataViewのデータ(抽出結果)からDataTableの位置を検索
DataSource(DataTable)を検索する

 
コメント
コメントする








    
この記事のトラックバックURL
トラックバック

calendar

S M T W T F S
1234567
891011121314
15161718192021
22232425262728
293031    
<< December 2019 >>

search this site.

よく使う、検索される投稿

categories

■Google AD■

アマゾン

楽天

selected entries

archives

recent comment

  • Macで作った大きなファイルをWindowsへ分割して転送する
    rockecco (11/18)
  • Macで作った大きなファイルをWindowsへ分割して転送する
    汐里 (11/17)
  • H3 SRB-3燃焼試験
    rockecco (08/30)
  • H3 SRB-3燃焼試験
    綿棒 (08/29)
  • ブレークポイントは現在の設定ではヒットしません〜ソリューションのデバッグ
    B.T (08/09)
  • 山の白い看板
    rockecco (06/06)
  • 山の白い看板
    田舎人 (05/08)
  • あの、クラスとかメソッドとかプルダウンできるバーって〜Visual Studio 2015
    rockecco (04/27)
  • あの、クラスとかメソッドとかプルダウンできるバーって〜Visual Studio 2015
    NS (04/27)
  • MacでBlu-ray編 〜 BD-Rを焼く その3 サポセン編
    rockecco (04/23)

recent trackback

profile


※当ブログはリンクフリーですが、 取材や雑誌等で掲載される場合は、事前にお知らせください

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM