ListBoxに色をつける

はじめに

ListBoxコントロールを色分けすることができるのか。というところから、掲示板でアドバイスを頂き、紹介されたのがGoldFishさんのカラーリストボックスでした。

もとはC#で書かれたプログラムなのですが、.NET同士ということでVBでも出来ないかと試してみたところ、同様の動作を行うことができました。見比べてみるのもまた一興かもしれません。というより、本当に「翻訳」なので、ろくに解説できないので、理解し試してみたい方は、GoldFishさんのサイトを併せて見てください。

なお、ほとんど「機械的な翻訳」を行った面が強く、「ここの処理はどういうことだ?」と聞かれても私が回答できない可能性大です。ソースの使用、利用は自己責任の上で行ってください。

GoldFishさんの了承を得、以下に手順とソースを公開します。快諾していただいたGoldFishさん、ありがとうございました。

and Special Thanks HEAT281@管理人様, よねKEN様

ColorListBox制作手順 - 1.クラスの追加

Windows アプリケーションのプロジェクトを作ります。フォームに適当に[ListBox]と[Button]を配置します。

form画面

メニューの[プロジェクト] - [クラスの追加]を選択。オリジナルのC#のプログラムと変わるところがありません。

プロジェクト

新しいクラスを作ります。拡張子が.vbになること以外は、全く同じ。ColorListBox.vbとしました。

クラス

さていよいよコードを書きます。クラスの宣言の前に、以下のものを追加します。

C#をVB.NETにするには、usingだったものをImportsに、また継承の書きかたも若干違います。

元のソースでは namespace 宣言がありますが、よく判らなかったので無しにしてみました。無事動いたし、無くていいのかな、と思った次第。

Imports System
Imports System.Windows.Forms
Imports System.Drawing
    ' <summary>
    ' ColorListBox の概要の説明です。
    ' </summary>
Public Class ColorListBox
    Inherits ListBox

以下、GoldFishさんのソースをコピペし、エラーの出たところを直していきます。

if文や、変数の宣言や初期化、改行のルールが違うので、VB式に書き直していきます。

最初の、Public Sub New() ですが、VB.NETでのコンストラクタはNewという名前のプロシージャと名前が固定なのだそうです(書いていて自分でも半分くらいしかわかってない)

    '// <summary>
    '// デフォルトコンストラクタ
    '// </summary>
    Public Sub New()
        '//TODO: コンストラクタ ロジックをここに追加してください。

        '// 高さを固定にする
        DrawMode = DrawMode.OwnerDrawFixed

        '// 派生元に色の情報をアイテムとして設定する
        Dim clr As Color
        clr = Color.FromArgb(0)

        Dim i As KnownColor
        For i = KnownColor.ActiveBorder To KnownColor.YellowGreen
            clr = Color.FromKnownColor(i)
            '// システム色でないものを追加する
            If clr.IsSystemColor = False Then
                Items.Add(clr)
            End If

        Next
    End Sub

ここまで書くと、以下のオーバーライドが自動的に作成されます。

C#では、OnDrawItem()も自動的に作成されるようですが、VB.NETでは自動的に作成されないようでした。

    '自動で作成されたオーバーライド、その1
    Protected Overrides Sub RefreshItem(ByVal index As Integer)
    End Sub
    '自動で作成されたオーバーライド、その2
    Protected Overrides Sub SetItemsCore(ByVal items As System.Collections.IList)
    End Sub

OnDrawItem()は自動では作成されないため、別に書きます。MSDN Library の[OnDrawItem Method]を参考にしました。

元はOverrides Protected Sub ...となってますが、そう書いても自動的にProtected Overrides Sub ...と変換されてしまいました。つまり後者のようにしか書けません。

また、タイプキャストの方法がわからずに苦戦しました。DirectCastを教えて戴き、解決しました。

    'アイテムを描画する
    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 clr As Color = DirectCast(Items(e.Index), Color)

        '// ブラシを作成
        Dim br As Brush
        br = New SolidBrush(clr)

        '// インデックスにあわせた描画する
        e.Graphics.FillRectangle(br, e.Bounds)

        '// 色の名前を書く
        Dim reclr As Color
        reclr = Color.FromArgb( _
        255 - clr.R, _
        255 - clr.G, _
        255 - clr.B)
        Dim rebr As Brush
        rebr = New SolidBrush(reclr)
        e.Graphics.DrawString(clr.Name, Font, rebr, e.Bounds.X, e.Bounds.Y)
        '// 選択されている場合
            If ((e.State And DrawItemState.Selected) = DrawItemState.Selected) Then
                '// 選択枠を描画する
                e.DrawFocusRectangle()
            End If
    End Sub

End Class

以上で、ColorListBoxクラスは完成。

制作手順 - 2.インスタンス作成部分の書き換え

フォームのコードを開きます。あらかじめ畳まれたコードを開きます。ココですね。

たたまれた部分

ListBox1のインスタンスを作成する部分がSystem.Windows.Forms.ListBoxとなってますが、そこをColorListBoxと置き換えれば完成です。正確には[プロジェクト名].ColorListBoxです(自動的に書き換えられてました)

#Region " Windows フォーム デザイナで生成されたコード "
    '(コード略)
    ' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
    'Windows フォーム デザイナを使って変更してください。  
    ' コード エディタを使って変更しないでください。
    Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
    Friend WithEvents Button1 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.ListBox1 = New ColorListBox
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'ListBox1
        '(以下コード略)

ここまで一度もコンパイルせずに作成してきた場合、Form1.vb[デザイン]ウィンドウで画面を確認すると、突然リストボックスが消失してビビリます。

リストボックスが消えた画像

一回コンパイルすれば、正しい表示が見れるはずです。それでもForm1.vb[デザイン]ウィンドウの表示がおかしい時は、一回VisualStudioを終了して再度立ち上げれば、正しい表示が見れると思います。

正しい表示状態

リストボックスにはTransparentから始まって、アルファベット順にYellowGreenまでが表示されます。

制作手順 - 3.ボタンの設定

ボタンのコードを書きます。リストボックスの色名をMessageBoxで表示するようにします。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim myitem As Object = ListBox1.SelectedItem
        If myitem Is "" Then
            Return
        End If
        Dim clr As Color = DirectCast(ListBox1.SelectedItem, Color)
        MessageBox.Show(clr.Name)
    End Sub

ボタンを押した状態

特定の色だけを表示する場合は、FormLoadを以下のようにします。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ListBox1.Items.Clear()
        ListBox1.Items.Add(Color.FromKnownColor(KnownColor.Red))
        ListBox1.Items.Add(Color.FromKnownColor(KnownColor.Blue))
        ListBox1.Items.Add(Color.FromKnownColor(KnownColor.LightGray))
    End Sub

このように表示されます。

三色表示

こういった表示そのものを利用したいと思う人はあまりいないと思いますが、こういった表示を応用したいと思う人は私だけではないかもしれません。そういった方々の参考になればと思います。


もどる | ListBoxに色をつける その2