Excel VBA 入力規則で2つの連動したプルダウンリストを作成する

ExcelVBA-実用編

今回はExcel機能の入力規則で、2つの連動したプルダウンリストを設定する方法をご説明します。

今回の方法はExcelの関数を使わずに、リストの作成をします。

Excelで入力規則を操作しても、データ構造等をしっかり組み立てる事で、2つまでの連動であれば比較的簡単に設定する事は出来ますが、それをVBAで作成します。

VBAで入力規則の基本的な操作方法と、データ構成も併せてご説明します。

Excelで入力規則を使用してプルダウンリストを作成する方法は「入力規則の基本説明と動的にプルダウンリストを作成する方法」をご覧ください。

また、VBAで入力規則の作成方法や、3つ以上の連動するリストの作成方法については、下記記事をご覧ください。

1.入力規則のリスト用のデータ構成

VBAで入力規則の連動したリストを作成するに2つまでは難しい構成は必要ありません。

それぞれの項目の階層が紐づくようにデータの一覧を作成します。

次のようなメーカーと商品が紐づくような一覧を用意しました。

そしてH4がH2で指定された文字列と連動するプルダウンリストを作成します。

2.入力規則の削除方法

セルに入力規則を設定する方法を説明する前に、入力規則の削除方法について説明します。

理由は、すでにセルに入力規則が設定されている場合はエラーとなります。

ですので、基本的に入力規則を設定する前に既存の入力規則を削除します。

削除するには設定されているセル(オブジェクト)の「Validationオブジェクト」を操作します。

記述方法は簡単で次のように記述します。

Range("設定されている範囲").Validation.Delete

3.入力規則のValidationオブジェクトと引数の説明

セルに入力規則を作るには、「Validationオブジェクト」の「Addメソッド」を使います。 

そして引数でそれぞれ詳細を設定します。

次のように記述します。

Validation.Add Type,AlertStyle,Operator,Formula1,Formula2

Validationの引数一覧

引数名省略説明
Type必須入力値の種類を指定します。
AlertStyle省略可能エラー時の動作を指定します。
Operator省略可能指定された値を比較する方法を指定します。
Formula1省略可能リストに指定したい値を指定します。
Formula2省略可能引数「Operator」で「xlBetween」もしくは「xlNotBetween」 を
指定した場合に、入力できる範囲の最大もしくは最小を指定します。
Typeの定数一覧

「Type」は 入力規則の種類を指定します。

Excelでは次の画面の操作になります。

定数数値説明
xlInputOnly0すべての値
xlValidateWholeNumber1整数
xlValidateDecimal2小数点
xlValidateList3リスト指定
xlValidateDate4日付指定
xlValidateTime5日時指定
xlValidateTextLength6文字列(長さ指定)
xlValidateCustom7ユーザ設定
AlertStyleの定数一覧

「AlertStyle」はエラー時の動作を指定します。

Excelでは次の画面の操作になります。

定数数値説明
xlValidAlertStop1停止
xlValidAlertWarning2注意
xlValidAlertInformation3情報
Operatorの定数一覧

「Operator」は指定された値を比較する方法を指定します。

「Type」で「 整数 」、「 小数点 」、「 日付指定 」、「日時指定」、「文字列(長さ指定)」 を選択時に指定する事ができます。

それ以外の「すべての値」、「リスト」、「ユーザ設定」では指定できません。

Excelでは次の画面の操作になります。

4.プルダウンリストの作成

まずは絞り込まれていないプルダウンリストを作成します。

そもそも「何も選択していない」状態では、どちらも全てのリストが選択できる状態である必要があります。

Sub List_Set()

Dim CheckDic    As Object
Dim MaxRow      As Long
Dim i           As Long
Dim n           As Long
Dim Myval       As String
Dim DicKey      As Variant
Dim ListStr     As String
 
With ActiveSheet
    
    '既存の入力規則を削除
    .Range("H2,H4").Validation.Delete
     
    'データを最終行取得する
    MaxRow = .Cells(Rows.Count, 2).End(xlUp).Row
    
    Set CheckDic = CreateObject("Scripting.Dictionary")
    
    '=========1つ目のリスト作成=========
    
    For n = 2 To 5  '項目数4列をループ
    
        Myval = Cells(2, n).Value '該当文字列を格納
            
        If Not CheckDic.exists(Myval) Then 'Dictionaryに登録して重複判定
    
            CheckDic.Add Myval, "" 'Dictionaryに登録
            
        End If
        
    Next n
    
    DicKey = CheckDic.keys 'Keyを変数に格納
        
    ListStr = Join(DicKey, ",") 'リストをカンマ区切りで統合して格納
    
    .Cells(2, 8).Validation.Add Type:=xlValidateList, Formula1:=ListStr
    
    '=========2つ目のリスト作成=========
    
    'データを最終行取得する
    MaxRow = .Cells(Rows.Count, 2).End(xlUp).Row
    
    Set CheckDic = CreateObject("Scripting.Dictionary") 'Dictionaryを初期化
    
    For n = 2 To 5 '項目数3列をループ
        
        For i = 3 To MaxRow '3行目から最終行までループ
            
            Myval = Cells(i, n).Value '該当文字列を格納
            
            If Not CheckDic.exists(Myval) Then 'Dictionaryに登録して重複判定
        
                CheckDic.Add Myval, "" 'Dictionaryに登録
                
            End If
        
        Next i
        
        DicKey = CheckDic.keys 'Keyを変数に格納
        
    Next n
            
    ListStr = Join(DicKey, ",") 'リストをカンマ区切りで統合して格納
     
    '入力規則を設定
    .Cells(4, 8).Validation.Add Type:=xlValidateList, Formula1:=ListStr
        
End With

End Sub

この様にすべてのリストが追加されました。

コードの説明です。

基本的にはコメントに何をしているか記載しています。

まずはお決まりの「.Range(“H2,H4”).Validation.Delete」で入力規則を一度削除します。

離れたセルを複数選択する場合は上記の様にカンマで区切ってセルを指定します。

まずは1つ目のリスト作成としてB3~E3まで列をループしてリストの文字列を格納します。

サンプルデータは重複していませんが、重複していないリストを作成するようにDictionaryを使用します。

Set CheckDic = CreateObject(“Scripting.Dictionary”)」で宣言します。

「Myval = Cells(2, n).Value」で該当文字列を格納してDictionaryのKeyに登録していきます。

DicKey = CheckDic.keys」でKeyを変数に格納して、「ListStr = Join(DicKey, “,”)」で変数をリスト用にカンマ区切りで統合して格納します。

「.Cells(2, 8).Validation.Add Type:=xlValidateList, Formula1:=ListStr」でH2にリストを追加します。

2つ目のリストも同様の方法で、行と列のループで一覧の中の商品をすべて格納して、最後にリストに追加します。

5.連動するプルダウンリストの作成

次に1つ目のプルダウンリストが選択された場合に、関連付く2つ目のリストを作成する方法です。

こちらはH2に指定された文字列をキーワードにして、列を取得してその該当列のリストを取得します。

まず2つ目のリストを作成するコードの前に、1つ目のリストが変更されたら2つ目のリストを絞り込むためのコードが実行されるイベントを用意します。

Worksheet_Changeを組み込む

H2のセルが変更されたらH6のリストを変更するためのコードが実行されるように、Worksheet_Change」にイベントを記載します。

今回はSheet1にリストを作成するので、Sheet1モジュールにコードを記述します。

Private Sub Worksheet_Change(ByVal Target As Range)

    If Target.Row = 2 And Target.Column = 8 Then
    
        Call List_Change(Target.Value)
        
    End If
    
End Sub

If Target.Row = 2 And Target.Column = 8 Then」で2行目、8列目のセルが変更されたときのみ実行されるように指定します。

Call List_Change(Target.Value)」でこれから作成する、H4のリストを作成するコードを呼び出しますが、1つ目のリストで指定されたここで値を渡します。

Target.Value」が選択したH2の値です。

2つ目のリストを作成する

次は標準モジュールに1つ目のリストに該当する列を取得して、その列にあるリスト一覧を格納してプルダウンリストに登録します。

Sub List_Change(ByVal GetStr As String)

Dim CheckDic    As Object
Dim MaxRow      As Long
Dim TargetCol   As Long
Dim n           As Long
Dim Myval       As String
Dim DicKey      As Variant
Dim ListStr     As String
 
With ActiveSheet

    If GetStr = "" Then '1つ目のリストが削除された場合はSetしなおす処理
    
        Call List_Set
        
    Else
    
        '2つ目の入力規則を削除
        .Range("H4").Validation.Delete
        
        '=========1つ目のリストを取得=========
        
        For n = 2 To 5  '項目数4列をループ
            
            If .Cells(2, n) = GetStr Then
            
                TargetCol = n
                Exit For
                
            End If
            
        Next n
        
        '=========2つ目のリスト作成=========
        
        'データを最終行取得する
        MaxRow = .Cells(Rows.Count, 2).End(xlUp).Row
        
        Set CheckDic = CreateObject("Scripting.Dictionary")
            
        For n = 3 To MaxRow '3行目から最終行までループ
            
            Myval = Cells(n, TargetCol).Value '該当文字列を格納
            
            If Not CheckDic.exists(Myval) Then 'Dictionaryに登録して重複判定
        
                CheckDic.Add Myval, "" 'Dictionaryに登録
                
            End If
        
        Next n
        
        DicKey = CheckDic.keys 'Keyを変数に格納
                
        ListStr = Join(DicKey, ",") 'リストをカンマ区切りで統合して格納
         
        '入力規則を設定
        .Cells(4, 8).Validation.Add Type:=xlValidateList, Formula1:=ListStr
        
    End If
        
End With

End Sub

コードの説明です。

「List_Change(ByVal GetStr As String)」の(ByVal GetStr As String)は先ほどの「Worksheet_Change」で取得した1つ目のリストの文字列を受け取るための宣言です。

「If GetStr = “” Then」で、もしリスト1つ目が削除された場合はエラーとなるため、最初に作った全てのリストを設定するコードを呼び出す処理です。

取得した文字列が空白ではない場合はリストの作成を行います。

.Range(“H4”).Validation.Delete」でH4のリストを一旦削除します。

列をループして、取得した文字列と一致する列を取得します。

この取得した列を「TargetCol = n」で格納して、2つ目のセルの列に使用します。

「Myval = Cells(n, TargetCol).Value」で該当列の文字列をループで最終行までDictionaryに格納します。

最後は同じです。

「DicKey = CheckDic.keys」でKeyを変数に格納して、Join関数でリスト用のカンマ区切りの文字列を作り、最後にH4にリストとして登録します。

無事H2にBメーカーと指定するとC列の関連したリストのみ登録出来ました。

6.ファイルを開いた時にリストを作成する

一番最初にリストを追加する場合に、ファイルを開いた時にリストを作成するように組み込むことで、リストが表示されないという事を避ける事ができます。

「ThisWorkbook」モジュールに次のように記述するだけです。

Private Sub Workbook_Open()
    Call List_Set
End Sub

ファイルを開いた時に自動で実行する方法の詳細については「ファイルを開く時にマクロを実行する方法」をご覧ください。

7.サンプルファイルダウンロード

今回は少し複雑な仕組みとなりましたので、今回使用したサンプルデータとサンプルコードをダウンロードできるようにします。

タイトルとURLをコピーしました