この記事でわかること
- ListBoxにAddItemで項目を追加して、ユーザーに1つ選ばせる基本操作
- MultiSelect + Selectedで複数項目を選択させる方法
- シートのデータをListBoxに読み込み→選択→別シートに転記する実務コード
対象: Excel 2016以降 / Microsoft 365、Windows 10/11
どんな場面で使う?
- 商品リストや社員リストからユーザーに複数項目を選ばせたいとき
- 手作業のスクロールとコピペを選択画面で置き換えたいとき
- 選択した項目だけを別シートに自動転記したいとき
- 検索キーワードで絞り込めるデータ選択UIを作りたいとき
—
完成イメージ(Before / After)
Before(手作業):
シートの一覧を目視でスクロール → 必要な行を見つけてコピー → 別シートにペースト → これを必要な件数分繰り返す
After(リストボックスで選択):
ユーザーフォームを開く → ListBoxに一覧が表示される → 必要な項目をクリックで選択(複数可) → 「転記」ボタンを押す → 選択データだけが別シートに自動転記される
—
自分も以前、シートにある100件以上の商品リストから必要な10件を手動で探してコピペしていた。スクロールして目視で探すのが正直しんどかった。リストボックスで選択画面を作ってからは、チェックして「実行」を押すだけ。探す時間がゼロになった。同じように一覧から手作業で探している人が、この記事で選択画面をサクッと作れるようになればうれしい。
ListBoxを使えば、シートのデータを一覧表示して、ユーザーに必要な項目だけを選ばせることができる。
なお、UserFormの基本的な作り方(フォームの挿入・コントロールの配置)は 入力フォーム(UserForm)で手入力ミスを防ぐ方法 を参照。この記事はListBoxの操作に集中する。
—
実行前の準備
バックアップを取る
実務版コードは転記先シートにデータを書き込む。必ずファイルのコピーを別フォルダに保存してから実行する。
Excelをマクロ有効ブック(.xlsm)で保存する
拡張子が .xlsx のままだとマクロが保存できない。
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
- 保存
—
手順(UserFormの作成 → コード貼り付けまで約10分)
Step 1: VBE(コードを書く画面)を開く
- Excelで
Alt + F11を押す
Step 2: ユーザーフォームを挿入する
- VBEのメニュー →「挿入」→「ユーザーフォーム」
- 空のフォーム(UserForm1)が表示される
- フォームのサイズを幅350×高さ300程度に調整する
Step 3: ListBoxを配置する
- ツールボックスが表示されていない場合は、メニュー→「表示」→「ツールボックス」
- ツールボックスの「リストボックス」(格子状のアイコン)をクリック
- フォーム上でドラッグしてListBoxを配置する(名前は
ListBox1のまま) - ListBoxのサイズを幅300×高さ200程度にする
Step 4: コマンドボタンを配置する
- ツールボックスの「コマンドボタン」アイコンをクリック
- フォーム上でドラッグしてボタンを配置(名前は
CommandButton1のまま) - ボタンのCaptionプロパティを「実行」に変更する(プロパティウィンドウで変更)
Step 5: コードを貼り付ける
- フォーム上でダブルクリック(または右クリック→「コードの表示」)
- UserFormのコードウィンドウが開く
- 下記のコードをそのまま貼り付ける
Step 6: 標準モジュールにフォーム表示用コードを貼り付ける
- VBEのメニュー →「挿入」→「標準モジュール」
- フォーム表示用のSubプロシージャを貼り付ける
Step 7: 実行する
Alt + F8→ShowListBoxFormを選んで「実行」
ボタンに割り当てれば毎回Alt+F8を押さなくて済む。方法は マクロをボタン1つで実行する方法 を参照。
—
コード(基本版)– AddItemでリストに項目を追加して1つ選択
まずはListBoxの動きを確認する最小コード。フォームを開くとリストに固定の項目が表示され、1つ選んで「実行」ボタンを押すとMsgBoxで選択結果を表示する。
UserFormモジュールに貼り付けるコード
'============================================================
' ■ ListBox基本版(UserFormモジュールに貼り付け)
' → フォームを開くとリストに項目を表示
' → 1つ選んで「実行」ボタンでMsgBox表示
'============================================================
Private Sub UserForm_Initialize()
'--- ListBoxに項目を追加(AddItem方式)
With Me.ListBox1
.Clear '← 既存の項目をクリア
.AddItem "商品A - 単価500"
.AddItem "商品B - 単価800"
.AddItem "商品C - 単価1200"
.AddItem "商品D - 単価300"
.AddItem "商品E - 単価950"
End With
End Sub
Private Sub CommandButton1_Click()
'--- 選択チェック
If Me.ListBox1.ListIndex = -1 Then
MsgBox "項目を選択してください。", vbExclamation
Exit Sub
End If
'--- 選択された項目を取得
Dim selectedItem As String
selectedItem = Me.ListBox1.List(Me.ListBox1.ListIndex)
MsgBox "選択: " & selectedItem, vbInformation
Unload Me
End Sub
標準モジュールに貼り付けるコード
'============================================================
' ■ フォーム表示用(標準モジュールに貼り付け)
'============================================================
Sub ShowListBoxForm()
UserForm1.Show
End Sub
書き換えポイント
| 箇所 | 説明 | 初期値 |
|---|---|---|
AddItem "商品A - 単価500" 等 |
リストに表示する項目 | 自分のデータに合わせて変更 |
ListBox1 |
ListBoxのコントロール名 | ListBox1(既定名のまま) |
CommandButton1 |
ボタンのコントロール名 | CommandButton1(既定名のまま) |
ポイント: ListIndex は0始まり。未選択時は -1 を返す。選択チェックには ListIndex = -1 を使う。
—
コード(実務版)– シートのデータを読み込み → 複数選択 → 別シートに転記
この方法を覚えてからは、月次の発注処理でもリストボックスから選択→自動転記にしている。手作業のコピペミスがなくなった。
前提のシート構成:
- 「データ」シート: A列に商品コード、B列に商品名、C列に単価(1行目はヘッダー)
- 「転記先」シート: 選択したデータの書き込み先(自動作成される)
※ 「転記先」シートの既存データはクリアされます。実行前にバックアップを取ってください。
UserFormモジュールに貼り付けるコード
'============================================================
' ■ ListBox実務版(UserFormモジュールに貼り付け)
' → 「データ」シートの一覧をListBoxに読み込み
' → 複数選択 → 「転記」ボタンで「転記先」シートに書き出し
'============================================================
'--- ★書き換えポイント ---
Private Const SOURCE_SHEET As String = "データ" '← データ元のシート名
Private Const TARGET_SHEET As String = "転記先" '← 転記先のシート名
Private Const START_ROW As Long = 2 '← データの開始行(1行目ヘッダー)
Private Const COL_COUNT As Long = 3 '← 表示する列数(A〜C列の3列)
'--- ★ここまで ---
Private Sub UserForm_Initialize()
'--- ListBoxの設定
With Me.ListBox1
.Clear
.ColumnCount = COL_COUNT '← 複数列を表示
.ColumnWidths = "80;120;60" '← 各列の幅(ポイント単位)
.MultiSelect = fmMultiSelectMulti '← クリックで複数選択
End With
'--- データシートから項目を読み込み
Dim wsSource As Worksheet
On Error Resume Next
Set wsSource = ThisWorkbook.Worksheets(SOURCE_SHEET)
On Error GoTo 0
If wsSource Is Nothing Then
MsgBox "「" & SOURCE_SHEET & "」シートが見つかりません。", vbExclamation
Unload Me
Exit Sub
End If
Dim lastRow As Long
lastRow = wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).Row
If lastRow < START_ROW Then
MsgBox "データがありません。", vbExclamation
Unload Me
Exit Sub
End If
'--- AddItemでシートのデータを読み込み
Dim r As Long
Dim c As Long
For r = START_ROW To lastRow
Me.ListBox1.AddItem wsSource.Cells(r, 1).Value '← 1列目を追加
For c = 2 To COL_COUNT
Me.ListBox1.List(Me.ListBox1.ListCount - 1, c - 1) = _
wsSource.Cells(r, c).Value '← 2列目以降を設定
Next c
Next r
'--- ボタンのキャプション設定
Me.CommandButton1.Caption = "選択データを転記"
Me.Caption = "データ選択画面"
End Sub
Private Sub CommandButton1_Click()
'--- 選択チェック(Selected をループして確認)
Dim i As Long
Dim c As Long
Dim hasSelection As Boolean
hasSelection = False
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Selected(i) Then
hasSelection = True
Exit For
End If
Next i
If Not hasSelection Then
MsgBox "項目を1つ以上選択してください。", vbExclamation
Exit Sub
End If
'--- 転記先シートの準備
Dim wsTarget As Worksheet
On Error Resume Next
Set wsTarget = ThisWorkbook.Worksheets(TARGET_SHEET)
On Error GoTo 0
'--- 転記先シートがなければ新規作成
If wsTarget Is Nothing Then
Set wsTarget = ThisWorkbook.Worksheets.Add(After:= _
ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
wsTarget.Name = TARGET_SHEET
End If
'--- 転記先をクリアしてヘッダーを書き込み
wsTarget.Cells.Clear
wsTarget.Cells(1, 1).Value = "商品コード"
wsTarget.Cells(1, 2).Value = "商品名"
wsTarget.Cells(1, 3).Value = "単価"
'--- 選択された項目を転記
Dim writeRow As Long
writeRow = 2
Dim transferCount As Long
transferCount = 0
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Selected(i) Then
For c = 0 To COL_COUNT - 1
wsTarget.Cells(writeRow, c + 1).Value = Me.ListBox1.List(i, c)
Next c
writeRow = writeRow + 1
transferCount = transferCount + 1
End If
Next i
MsgBox transferCount & " 件のデータを「" & TARGET_SHEET & "」シートに転記しました。", vbInformation
Unload Me
End Sub
標準モジュールに貼り付けるコード
'============================================================
' ■ フォーム表示用(標準モジュールに貼り付け)
'============================================================
Sub ShowListBoxForm()
UserForm1.Show
End Sub
書き換えポイント
| 変数/定数 | 説明 | 初期値 |
|---|---|---|
SOURCE_SHEET |
データ元のシート名 | "データ" |
TARGET_SHEET |
転記先のシート名 | "転記先" |
START_ROW |
データの開始行 | 2(1行目はヘッダー) |
COL_COUNT |
表示する列数 | 3(A〜C列) |
ColumnWidths |
各列の表示幅 | "80;120;60" |
| ヘッダーの文字列 | 転記先シートのヘッダー | 自社のデータに合わせて変更 |
シート構成の例
「データ」シート(データ元):
| A列(商品コード) | B列(商品名) | C列(単価) |
|---|---|---|
| P001 | ボールペン(黒) | 120 |
| P002 | ノートA5 | 250 |
| P003 | クリアファイル | 80 |
| P004 | 付箋(大) | 350 |
| P005 | ホッチキス | 480 |
「転記先」シート(実行後) — P001, P003, P005 を選択した場合:
| A列(商品コード) | B列(商品名) | C列(単価) |
|---|---|---|
| P001 | ボールペン(黒) | 120 |
| P003 | クリアファイル | 80 |
| P005 | ホッチキス | 480 |
—
よくある落とし穴5選
1. RowSourceで別シートのデータが表示されない
自分もこれでハマった。RowSourceに "A2:A100" だけ指定して、別シートがアクティブのときにフォームを開いたら空リストが表示された。原因に気づくまで30分溶かした。
原因: RowSourceにシート名を含めないと、アクティブシートの範囲が参照される。
対策: 必ずシート名を含める。"データ!A2:C100" のように書く。AddItem方式ならこの問題は起きない。
2. AddItemとRowSourceを同時に使ってエラーになる
原因: RowSourceが設定されている状態で AddItem を呼ぶと「プロパティまたはメソッドが無効です」というエラーが出る。
対策: AddItem方式を使う場合は、先に ListBox1.RowSource = "" でRowSourceをクリアする。プロパティウィンドウでRowSourceが空になっていることも確認する。
3. MultiSelectなのにListIndexだけで取得して1件しか取れない
原因: MultiSelectモードでは ListIndex は最後にクリックした項目のインデックスしか返さない。複数選択した項目は Selected(i) でしか取得できない。
対策: For i = 0 To ListBox1.ListCount - 1 のループで Selected(i) をチェックする。実務版コードのパターンをそのまま使えばOK。
4. ListBoxのインデックスが0始まりでExcelの行番号とずれる
原因: ListBoxの List(i) や Selected(i) は0始まり。Excelの行番号は1始まり。さらにヘッダー行があるとさらに1ずれる。
対策: シートの行番号に変換するには 行番号 = i + START_ROW のように開始行を足す。実務版コードではAddItemで値を直接格納しているので行番号の変換は不要。
5. Unload Meを忘れてフォームがメモリに残り続ける
原因: Me.Hide は非表示にするだけで、フォームオブジェクトはメモリに残る。連続で ShowListBoxForm を呼ぶと前回のデータが残る場合がある。
対策: 処理完了後は Unload Me でフォームを破棄する。次回表示時に UserForm_Initialize が再実行されるので、常に最新データが読み込まれる。
—
VBAのListBoxに項目が表示されないときの対処法
「ListBoxを配置したのに項目が空のまま」という場合、原因はRowSourceとAddItemの競合か、シート名の未指定だ。RowSourceを使うならシート名を含めて指定する。AddItemを使うならRowSourceを空にしてから追加する。
VBAのListBoxで複数選択した項目を取得できないときの対処法
「MultiSelectモードなのに選択が1件しか取れない」という場合、原因はListIndexだけで取得しようとしていること。MultiSelectモードでは Selected(i) をループで全件チェックする必要がある。
FAQ
Q1: AddItemとRowSourceはどちらを使うべき?
条件付きでデータを絞り込みたい場合はAddItem。シートのデータをそのまま表示するだけならRowSourceが手軽。
| 場面 | 推奨 |
|---|---|
| シートの一覧をそのまま表示 | RowSource(ListBox1.RowSource = "データ!A2:C100") |
| 条件に合うデータだけ表示 | AddItem(ループ内でIf文で判定してから追加) |
| フォーム上で動的に項目を追加/削除 | AddItem + RemoveItem |
AddItemで条件付き追加をするパターンは、InputBoxで条件を入力させて絞り込むのにも使える。詳しくは InputBoxで条件を入力させて処理を動的に変える方法 を参照。
Q2: ListBoxに複数列を表示するには?
ColumnCount で列数を指定し、ColumnWidths で各列の幅を設定する。
With Me.ListBox1
.ColumnCount = 3 '← 3列表示
.ColumnWidths = "80;120;60" '← 各列の幅
End With
AddItemで複数列のデータを入れる場合は、1列目は AddItem で追加し、2列目以降は List(行, 列) で設定する。
Me.ListBox1.AddItem wsSource.Cells(r, 1).Value '← 1列目
Me.ListBox1.List(Me.ListBox1.ListCount - 1, 1) = wsSource.Cells(r, 2).Value '← 2列目
Me.ListBox1.List(Me.ListBox1.ListCount - 1, 2) = wsSource.Cells(r, 3).Value '← 3列目
Q3: 選択をリセット(全解除)するボタンを付けるには?
フォームにもう1つCommandButtonを追加し、以下のコードを書く。
Private Sub CommandButton2_Click()
Dim i As Long
For i = 0 To Me.ListBox1.ListCount - 1
Me.ListBox1.Selected(i) = False
Next i
End Sub
Q4: 応用: リストの項目数が多いとき、検索で絞り込むには?
TextBoxを1つ追加し、Changeイベントで入力文字に合致する項目だけをAddItemし直す。
'※ 実務版コードの定数(SOURCE_SHEET, START_ROW, COL_COUNT)を使用
Private Sub TextBox1_Change()
Dim keyword As String
keyword = Me.TextBox1.Value
Me.ListBox1.Clear
Dim wsSource As Worksheet
Set wsSource = ThisWorkbook.Worksheets(SOURCE_SHEET)
Dim lastRow As Long
lastRow = wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).Row
Dim r As Long
For r = START_ROW To lastRow
'--- 商品コードまたは商品名にキーワードが含まれていれば追加
If InStr(1, wsSource.Cells(r, 1).Value, keyword, vbTextCompare) > 0 Or _
InStr(1, wsSource.Cells(r, 2).Value, keyword, vbTextCompare) > 0 Then
Me.ListBox1.AddItem wsSource.Cells(r, 1).Value
Me.ListBox1.List(Me.ListBox1.ListCount - 1, 1) = wsSource.Cells(r, 2).Value
Me.ListBox1.List(Me.ListBox1.ListCount - 1, 2) = wsSource.Cells(r, 3).Value
End If
Next r
End Sub
リストの重複を除去してから表示したい場合は Dictionaryで重複チェック・集計を高速化する方法 が参考になる。
Q5: ListBoxとComboBoxの違いは?
| 比較 | ListBox | ComboBox |
|---|---|---|
| 表示 | 常にリストが見える | クリックで展開するドロップダウン |
| 複数選択 | MultiSelectで可能 | 不可(1つだけ) |
| フォーム上の面積 | 大きい | 小さい |
| 用途 | 複数選択が必要な場面 | 1つだけ選ばせる場面 |
1つだけ選ばせるなら場所を取らないComboBoxが向いている。複数選択が必要ならListBox一択。UserFormでのComboBox活用は ユーザーフォームで本格的な入力画面を作る方法 を参照。
—
まとめ
- AddItem: 項目を1つずつ追加。条件付き絞り込みに向いている
- RowSource: セル範囲を一括バインド。シートデータをそのまま表示するなら手軽
- MultiSelect:
fmMultiSelectMultiでクリック選択/解除、fmMultiSelectExtendedでShift/Ctrl選択 - Selected(i): ループで全項目をチェックして、選択された項目だけ処理する
- 未選択チェック:
ListIndex = -1(単一選択時)またはSelected(i)のループ(複数選択時)で確認 - Option Explicit: UserFormモジュールの先頭に追加しておくと、変数名のタイプミスを防げる
関連記事
- 入力フォーム(UserForm)で手入力ミスを防ぐ方法 — UserFormの基本操作(フォームの挿入・コントロールの配置)
- エラー処理(On Error)で止まらないマクロを作る方法 — フォーム処理でのエラーハンドリング
- セルの転記を自動化(別シートへのコピペ不要に) — ListBoxから取得したデータの転記テクニック
—
次にやりたくなること
- 入力規則(ドロップダウンリスト)をVBAで一括設定する方法: フォームを使わずにセル上でデータを選ばせたい場合
- ユーザーフォームで本格的な入力画面を作る方法: TextBox・ComboBox・CheckBoxを組み合わせた本格的な入力フォームを作りたい場合
- Dictionaryで重複チェック・集計を高速化する方法: ListBoxに表示するデータの重複を事前に除去したい場合


コメント