【VBA】入力規則のプルダウンを動的に変更する

Excelの入力規則のプルダウンを別のセルの選択内容に連動して切り替える機能をVBAで書いてみます。 カテゴリを選ぶと、それに対応するサブカテゴリだけが選べるようになる連動プルダウンです。

標準機能との比較

この連動プルダウンは、Excelの関数でも実現できます。
カテゴリごとに名前定義を作り、入力規則の元の値でINDIRECT関数を使う方法です。
ただしこの方法には、マスタ側のレイアウトに制約があります。

方式 マスタの形
INDIRECT+名前定義 カテゴリごとに項目を分けた表
VBA カテゴリとサブカテゴリの対応表

カテゴリが頻繁に増える入力フォームでは、対応表1枚で済むVBA方式のほうが管理がしやすいです。

マスタシートのレイアウト

マスタシートを、カテゴリとサブカテゴリの対応表として作成します。
A列にカテゴリ、B列にサブカテゴリを並べます。

マスタシートのD列もVBAの作業列として使用します。
カテゴリに一致したサブカテゴリをVBAが書き出す列なので、手入力はしません。

選択シートのレイアウト

選択シートのA2セルにカテゴリ、B2セルにサブカテゴリを選択する入力欄を作ります。

A2でカテゴリ1を選ぶと、B2のプルダウンにサブカテゴリ1-1サブカテゴリ1-2だけが現れます。

事前準備

まずA2セルにカテゴリ用の入力規則を設定します。
この部分は標準機能で問題ありません。

  1. 選択シートのA2セルを選択
  2. 「データ」タブ →「データの入力規則」
  3. 入力値の種類を「リスト」にする
  4. 元の値に=マスタ!$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)かどうかは、TargetRowColumnで判定します。

リストはマスタから動的に組み立てています。
A列が選択されたカテゴリと一致する行だけを取得し、サブカテゴリをマスタシートのD列に書き出します。
書き出した範囲をFormula1"=マスタ!$D$2:$D$◯"の形で渡すことで、プルダウンの選択肢が差し替わります。

カンマ区切りの文字列をFormula1に直接渡す方法もありますが、255文字までという制限があります。 範囲参照の形なら項目数を気にしなくても良いので、この形にしています。

もう1点、Application.EnableEventsでのイベント制御が必要です。
B2のClearContentsWorksheet_Changeを呼び出してしまうため、このままでは無限ループの恐れがあります。 セル操作の前後でイベントを無効化して回避しています。

動作確認

選択シートのA2でカテゴリ1を選択すると、B2のセルをクリックしたときのプルダウンに
サブカテゴリ1-1サブカテゴリ1-2だけが表示されます。

続けてA2でカテゴリ2に選び直すとB2はクリアされ、
プルダウンもサブカテゴリ2-1サブカテゴリ2-2に切り替わります。

注意点

  • 入力規則が設定済みのセルにはValidation.Addをそのまま呼び出せないため、先にValidation.Deleteしてから組み直しています
Licensed under CC BY-NC-SA 4.0
Hugo で構築されています。
テーマ StackJimmy によって設計されています。