ListBoxに色をつける その2

任意の項目に色をつける

元は、リストボックスで任意の項目に色をつけたい。そう思っていたのですが、前項のColorListBoxをどう応用すれば良いのか、あれこれいじりながら探ってましたが、私の知識と技量ではあまり進展しませんでした。

そんな時、VisualBasic初心者連盟の管理人HEAT281様からアドバイスを戴き、望んだとおりの動作が得られました。前項ColorListBoxを以下のように改造することで、任意の項目の文字色を変えることができます。

ColorListBox.vb の変更

コンストラクタの、色情報をアイテムにするループをざっくりカットします。

    '(略)
    Public Sub New()
        '//TODO: コンストラクタ ロジックをここに追加してください。

        '// 高さを固定にする
        DrawMode = DrawMode.OwnerDrawFixed
    End Sub
    '(以下略)

OnDrawItemメソッド部分を以下のように変更します。どの色を呼び出すかは、ここで決めます。

    Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
        '// 派生元はコールしない
        '// base.OnDrawItem (e);

        '// 描画するインデックスをチェック
        If e.Index = -1 Then
            Return
        End If

        '// 描画する範囲を取得
        Dim rc As Rectangle
        rc = e.Bounds

        'アイテム文字列の取得
        Dim itm As String = Items(e.Index).ToString()
        Dim s As String
        Dim clrString As Color
        clrString = Color.FromArgb(0, 0, 0)

        If itm.Length >= 3 Then
            Dim sl As String = itm.Substring(0, 1) '1文字目を取得
            Dim sc As String = itm.Substring(1, 1) '2文字目を取得
            Dim sr As String = itm.Substring(2, 1) '3文字目を取得

            If sl = "<" And sr = ">" Then
                Select Case sc
                    Case "0"  '黒
                        clrString = Color.FromArgb(0, 0, 0)
                    Case "1"  '赤
                        clrString = Color.FromArgb(255, 0, 0)
                    Case "2"  '緑
                        clrString = Color.FromArgb(0, 128, 0)
                    Case "3"  '青
                        clrString = Color.FromArgb(0, 0, 255)
                    Case Else 'その他の場合は黒
                        clrString = Color.FromArgb(0, 0, 0)
                End Select
                If itm.Length > 3 Then
                s = itm.Substring(3)  'タグの後の文字列を取得
                Else
                    s = ""  'タグだけの場合、表示する文字列は無し
                End If
            Else
                s = itm
            End If
        Else
            s = itm
        End If

        '// 背景色は白で固定
        Dim clr As Color = Color.FromArgb(255, 255, 255)
        Dim br As Brush
        br = New SolidBrush(clr)
        e.Graphics.FillRectangle(br, e.Bounds)

        '// アイテムを書く
        Dim rebr As Brush
        rebr = New SolidBrush(clrString)
        e.Graphics.DrawString(s, Font, rebr, e.Bounds.X, e.Bounds.Y)
        '// 選択されている場合
        If ((e.State And DrawItemState.Selected) = DrawItemState.Selected) Then
            '// 選択枠を描画する
            e.DrawFocusRectangle()
        End If
    End Sub

Form1_Loadに追加

Form1_Loadに以下のコードを追加します。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ListBox1.Items.Clear()
        ListBox1.Items.Add("<0>黒で描画")
        ListBox1.Items.Add("<1>赤で描画")
        ListBox1.Items.Add("<2>緑で描画")
        ListBox1.Items.Add("<3>青で描画")
        ListBox1.Items.Add("何も指定が無い場合は黒で描画")
    End Sub

コンパイル後はこのようになります。

任意の文字色

以上、サンプルでは<[数字]>を先頭に置くことで描画色を変更するようにしてますが、実装時はユーザーが使わなそうな文字、たとえば%[数字]$などにすると良いかもしれません。

その他の課題

リストボックスの選択された項目は、(Windowsをカスタマイズしていなければ)普通は青バック白文字、選択枠が出るという表示になると思います。

今回、文字色や背景色をいじる都合上、選択状態を示すものは枠だけに頼る形になりましたが、枠は起動後にTABキーでフォーカスを合わせるまで出ません。

これは、ColorListBoxに問題があるというわけではなく、大元のListBoxの持つバグ?のようです。背景色や文字色変更があるために普段は目立ちませんが。

上記のソースを使用する場合は、以上の特性も踏まえて実装するとよいかと思います。


もどる