【コピペでOK!】ユーザーフォームにリストボックスを追加する方法を4パターン紹介

アイキャッチ
リストボックスにデータを追加する方法
  • ListBox1.AddItem 変数で変数に代入された値をリストボックスに追加します
  • ListBox1.List = Range(“名前”).Valueで定義された”名前”をリストに追加します
  • ListBox1.RowSource = “名前”で定義された”名前”をリストに追加します
  • 重複データを削除してリストボックスに追加するにはDictionaryオブジェクトを使用します

エクセルファイルの操作を間違えないよう誘導するのに、ユーザーフォームは非常に便利です。AddItemメソッドListプロパティRowSourceプロパティDictionaryオブジェクト(重複削除)を使ってリストボックスにデータを追加する方法を紹介します。

目次

コードのみで完結するリストボックス

追加するリストを全てコードの中で指定する方法です。ファイルを操作する人にリストを触られたくないケースや、一度作ってしまえばほぼリストの更新がないケースはこの方法がおすすめです。

AddItemメソッドでデータを追加

STEP
ユーザーフォームの作成
ユーザーフォーム作成画面の画像。ListBox1がフォーム内に作成されている。

挿入ユーザーフォームでフォームを作成し、表示ツールボックスリストボックスを選択、フォーム内に適当なサイズで作成します。フォントはプロパティウィンドウで調整して下さい。

STEP
フォームモジュールにコードを記述

フォームモジュールでUserForm_Initializeイベントを使用して、リストボックスを追加します。

Private Sub UserForm_Initialize()
    Dim 守備位置 As Variant
    Dim r As Variant

    守備位置 = Array("内野手", "外野手", "投手", "捕手") '※1
    
    For Each r In 守備位置
        ListBox1.AddItem r '※2
    Next r
    
    ListBox1.ListIndex = 0 '※3
End Sub
  1. 5行目…Array関数を使って、配列の要素としてテーブルを指定しています。
  2. 8行目…AddItemメソッドでリストを追加しています。
  3. 11行目…デフォルトのカーソル位置を指定しています。-1で非選択状態になります。

ワークシートのデータを利用するリストボックス

シートのデータを参照するのに名前の定義を使用します。OFFSET関数で参照範囲を可変させているので、データを更新(追加・削除)してもコードの変更は不要です。ただし、後述しますが初期化以降にデータを更新した場合、リストボックスに更新を反映するにはひと手間必要です。

Listプロパティでデータを追加

STEP
ユーザーフォームの作成
ユーザーフォーム作成画面の画像。ListBox1がフォーム内に作成されている。

挿入ユーザーフォームでフォームを作成し、表示ツールボックスリストボックスを選択、フォーム内に適当なサイズで作成します。フォントはプロパティウィンドウで調整して下さい。

STEP
名前の定義
名前の定義ダイアログの画像。OFFSET関数で参照範囲を可変させる数式が入力されている。

リストボックスに追加するデータを定義します。A列1行目がフィールド名、以降をフィールドとして、参照範囲を=OFFSET(Sheet1!$A$2,,,COUNTA(Sheet1!$A:$A)-1)とします。ただし、データが空だとフィールド名を参照してしまいます。

STEP
フォームモジュールにコードを記述

リストボックスのデータは2次元配列です。前項のAddItemメソッドは空の配列に1件ずつデータを追加しますが、ワークシートのデータを利用すれば、Listプロパティでまとめて追加できます。

Private Sub UserForm_Initialize()
    With ListBox1
        .List = Range("リスト").Value '※1
        .ListIndex = 0
    End With
End Sub
  1. 3行目…Range(“名前”).Valueで、定義した名前を配列として扱えます(Value省略不可)。

データが更新(追加/削除)されても即座にはリストボックスに反映されません。再イニシャライズ するか、一度データをクリア(Clearメソッド)して再登録する必要があります。

RowSourceプロパティでデータを追加

このパターンが一番おすすめです。このプロパティを使用すると、リストボックスのメソッドであるAddItemClearRemoveItemが使用できなくなります(=コード上でデータの更新ができない)が、RowSourceプロパティ名前の定義を組み合わせる事で、シート上のデータ更新を即時リストボックスへ反映させる事ができます。

STEP
ユーザーフォームの作成
ユーザーフォーム作成画面の画像。ListBox1がフォーム内に作成されている。

挿入ユーザーフォームでフォームを作成し、表示ツールボックスリストボックスを選択、フォーム内に適当なサイズで作成します。フォントはプロパティウィンドウで調整して下さい。

STEP
名前の定義
名前の定義ダイアログの画像。OFFSET関数で参照範囲を可変させる数式が入力されている。

リストボックスに追加するデータを定義します。A列1行目がフィールド名、以降をフィールドとして、参照範囲を=OFFSET(Sheet1!$A$2,,,COUNTA(Sheet1!$A:$A)-1)とします。ただし、データが空だとフィールド名を参照してしまいます。

STEP
フォームモジュールにコードを記述
Private Sub UserForm_Initialize()
    With ListBox1
        .RowSource = "リスト" '※1
        .ListIndex = 0
    End With
End Sub
  1. 3行目…RowSourceプロパティは文字列で指定する必要があります。RangeオブジェクトAddressプロパティを使用するならRowSource = Range(“リスト”).Addressとします。

重複データを削除したリストボックス

Dictionaryオブジェクトでデータを追加

絞り込み検索(抽出)用のリストボックスを作成したい場合等、重複データを削除したいケースがあります。重複データを削除するのにDictionaryオブジェクトを利用します。

Dictionaryオブジェクト連想配列とも呼ばれるそうですが、配列はインデックス番号と要素がセットで格納されるのに対し、連想配列はキーとデータがセットで格納されます。この「キー」が重複を許さない仕様を利用して重複データを削除(=重複したデータは追加しない)します。

Dictionaryオブジェクトについてはこのサイトを参考にしました。

STEP
ユーザーフォームの作成
ユーザーフォーム作成画面の画像。ListBox1がフォーム内に作成されている。

挿入ユーザーフォームでフォームを作成し、表示ツールボックスリストボックスを選択、フォーム内に適当なサイズで作成します。フォントはプロパティウィンドウで調整して下さい。

STEP
テーブルデータを用意
データシートの画像。フィールド数12のテーブルが表示されている。

テーブルA列に重複削除したいフィールドがあるテーブルを用意して下さい。スクショの場合、内野手,外野手,投手,捕手,がリストボックスに追加されます。

STEP
フォームモジュールにコードを記述
Private Sub UserForm_Initialize()
    Dim dicオブジェクト As Object
    Dim r As Variant, s As Variant
    Dim バッファ As String

    With Worksheets("Sheet1")
        Set dicオブジェクト = CreateObject("Scripting.Dictionary") '※1
        If .Cells(Rows.Count, 1).End(xlUp).Row = 1 Then Exit Sub

        For Each r In .Range(.Cells(2, 1), .Cells(Rows.Count, 1).End(xlUp))
            バッファ = r.Value
            If Not dicオブジェクト.Exists(バッファ) Then '※2
                dicオブジェクト.Add バッファ, ""
            End If
        Next r
    End With

    For Each s In dicオブジェクト.Keys '※3
        ListBox1.AddItem s
    Next s

    Set dicオブジェクト = Nothing
    ListBox1.ListIndex = 0
End Sub
  1. 7行目…Dictionaryオブジェクトは外部ライブラリ(Microsoft Scripting Runtime)のクラスです。参照設定しているのであれば、2行目はDim dicオブジェクト As New DictionaryでOKです(可能ならこちらを推奨)。
  2. 12行目…キー変数バッファ、データには“”を代入しています。今回は「キーが重複を許さない仕様」のみを利用しているので、データは何でも構いません。必要なのは「キー」だけです。
  3. 18~20行目…キーdicオブジェクト.KeysAddItemメソッドリストボックスに追加します。

参照設定についてはこの記事で紹介しています。

番外編:CreateObjectが原因でエラー

前項コードの18~20行目、Keysメソッドでキーを取り出そうとした場合、CreateObject関数を使用しているとエラーになります。

Private Sub UserForm_Initialize()
    Dim dicオブジェクト As Object
    Dim r As Variant
    Dim i As Long
    Dim バッファ As String

    With Worksheets("Sheet1")
        Set dicオブジェクト = CreateObject("Scripting.Dictionary")
        If .Cells(Rows.Count, 1).End(xlUp).Row = 1 Then Exit Sub

        For Each r In .Range(.Cells(2, 1), .Cells(Rows.Count, 1).End(xlUp))
            バッファ = r.Value
            If Not dicオブジェクト.Exists(バッファ) Then
                dicオブジェクト.Add バッファ, ""
            End If
        Next r
    End With
'ループカウンタでKeysを1件ずつ取り出そうとした場合
    For i = 0 To dicオブジェクト.Count - 1
        ListBox1.AddItem dicオブジェクト.Keys(i) '※1 ここでエラーが出る
    Next i

    Set dicオブジェクト = Nothing
    ListBox1.ListIndex = 0
End Sub
  1. 19行目実行時に「Property Let プロシージャが定義されておらず、Property Get プロシージャからオブジェクトが返されませんでした」とエラーを吐かれます(エラー 451)。

色々調べて、回避する方法を3つ見つけました。

パターン
変数追加

dicオブジェクト.Keysを変数に入れます。VBAリファレンスにはこの方法が載っているので、これが正式な記述方法です。

Dim vKey as Variant
    vKey = dicオブジェクト.Keys

    For i = 0 To dicオブジェクト.Count - 1
        ListBox1.AddItem vKey(i)
    Next i
パターン
“()”追加

dicオブジェクト.Keysの直後に()を追加します。理屈はよくわかりません。

    For i = 0 To dicオブジェクト.Count - 1
        ListBox1.AddItem dicオブジェクト.Keys()(i)
    Next i
パターン
Microsoft Scripting Runtimeを参照設定する

参照設定を使用するコードだと、そもそものエラーは出ません。何がなんだかわからない…

Private Sub UserForm_Initialize()
    Dim r As Variant
    Dim i As Long
    Dim バッファ As String
    Dim dicオブジェクト As New Dictionary

    With Worksheets("Sheet1")
        If .Cells(Rows.Count, 1).End(xlUp).Row = 1 Then Exit Sub

        For Each r In .Range(.Cells(2, 1), .Cells(Rows.Count, 1).End(xlUp))
            バッファ = r.Value
            If Not dicオブジェクト.Exists(バッファ) Then
                dicオブジェクト.Add バッファ, ""
            End If
        Next r
    End With

    For i = 0 To dicオブジェクト.Count - 1
        ListBox1.AddItem dicオブジェクト.Keys(i) 'エラーが出ない
    Next i

    Set dicオブジェクト = Nothing
    ListBox1.ListIndex = 0
End Sub

理解はできていませんが、エラーの回避方法でした。

リストボックスへデータを追加する方法を4パターン紹介しました。AddItemメソッドを使用する方法、Listプロパティを使用する方法、RowSourceプロパティを使用する方法、それぞれにいいところがあります。

ここでは触れませんでしたが2列以上のデータを扱う場合はAddItemメソッドでは対応できませんし、AddItemClearRemoveItemを使用しないのであれば、RowSourceプロパティは大変お手軽で便利です。

一つの方法に固執するのではなく、状況に応じて使い分ける事をおすすめします。

よかったらシェアしてね!
  • URLをコピーしました!
目次