Excelの入力規則のプルダウンを別のセルの選択内容に連動して切り替える機能をVBAで書いてみます。 カテゴリを選ぶと、それに対応するサブカテゴリだけが選べるようになる連動プルダウンです。
標準機能との比較
この連動プルダウンは、Excelの関数でも実現できます。
カテゴリごとに名前定義を作り、入力規則の元の値でINDIRECT関数を使う方法です。
ただしこの方法には、マスタ側のレイアウトに制約があります。
| 方式 | マスタの形 |
|---|---|
| INDIRECT+名前定義 | カテゴリごとに項目を分けた表 |
| VBA | カテゴリとサブカテゴリの対応表 |
カテゴリが頻繁に増える入力フォームでは、対応表1枚で済むVBA方式のほうが管理がしやすいです。
マスタシートのレイアウト
マスタシートを、カテゴリとサブカテゴリの対応表として作成します。
A列にカテゴリ、B列にサブカテゴリを並べます。
マスタシートのD列もVBAの作業列として使用します。
カテゴリに一致したサブカテゴリをVBAが書き出す列なので、手入力はしません。
選択シートのレイアウト
選択シートのA2セルにカテゴリ、B2セルにサブカテゴリを選択する入力欄を作ります。
A2でカテゴリ1を選ぶと、B2のプルダウンにサブカテゴリ1-1とサブカテゴリ1-2だけが現れます。
事前準備
まずA2セルにカテゴリ用の入力規則を設定します。
この部分は標準機能で問題ありません。
選択シートのA2セルを選択- 「データ」タブ →「データの入力規則」
- 入力値の種類を「リスト」にする
- 元の値に
=マスタ!$A$2:$A$5を入力
VBAコードは標準モジュールではなく、選択シートのシートモジュールに書く点に注意してください。
VBAコード
選択シートのシートモジュールに、次のWorksheet_Changeイベントプロシージャを書きます。
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
' A2セル以外の変更は何もしない
If Target.Row <> 2 Or Target.Column <> 1 Then
Exit Sub
End If
Dim selectSht As Worksheet
Set selectSht = ThisWorkbook.Worksheets("選択")
Dim masterSht As Worksheet
Set masterSht = ThisWorkbook.Worksheets("マスタ")
' ClearContentsもChangeイベントを発生させるため、イベントを止めてからクリアする
Application.EnableEvents = False
selectSht.Range("B2").ClearContents
Application.EnableEvents = True
' 作業列(D列)の前回分を消す
Dim lastRow As Long
lastRow = masterSht.Cells(masterSht.Rows.Count, 1).End(xlUp).Row
masterSht.Range(masterSht.Cells(2, 4), masterSht.Cells(lastRow, 4)).ClearContents
' カテゴリに一致するサブカテゴリを作業列に書き出す
Dim writeRow As Long
writeRow = 2
Dim i As Long
For i = 2 To lastRow
If masterSht.Cells(i, 1) = selectSht.Range("A2") Then
masterSht.Cells(writeRow, 4) = masterSht.Cells(i, 2)
writeRow = writeRow + 1
End If
Next i
' 一致するサブカテゴリがなければ何もしない
If writeRow = 2 Then
Exit Sub
End If
' B2セルの入力規則を組み直す
With selectSht.Range("B2").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Formula1:="=マスタ!$D$2:$D$" & (writeRow - 1)
End With
End Sub
変更されたセルがカテゴリセル(A2)かどうかは、TargetのRowとColumnで判定します。
リストはマスタから動的に組み立てています。
A列が選択されたカテゴリと一致する行だけを取得し、サブカテゴリをマスタシートのD列に書き出します。
書き出した範囲をFormula1に"=マスタ!$D$2:$D$◯"の形で渡すことで、プルダウンの選択肢が差し替わります。
カンマ区切りの文字列をFormula1に直接渡す方法もありますが、255文字までという制限があります。
範囲参照の形なら項目数を気にしなくても良いので、この形にしています。
もう1点、Application.EnableEventsでのイベント制御が必要です。
B2のClearContentsもWorksheet_Changeを呼び出してしまうため、このままでは無限ループの恐れがあります。
セル操作の前後でイベントを無効化して回避しています。
動作確認
選択シートのA2でカテゴリ1を選択すると、B2のセルをクリックしたときのプルダウンに
サブカテゴリ1-1とサブカテゴリ1-2だけが表示されます。
続けてA2でカテゴリ2に選び直すとB2はクリアされ、
プルダウンもサブカテゴリ2-1とサブカテゴリ2-2に切り替わります。
注意点
- 入力規則が設定済みのセルには
Validation.Addをそのまま呼び出せないため、先にValidation.Deleteしてから組み直しています