• ベストアンサー

【Excel】 数階層のドロップダウンリストを設定

Excel2007を使っています。 B3を分類の「A、B、C」のドロップダウンリストから選択します。 ※別表のG3:G16を元にしますが、「A、A、A、A、A、A、B、B、B・・・」とならないようにしたいです。 また、B3に「A」を選んだ場合、C3に「DDD、EEE、FFF」のドロップダウンが表示され、 C3に「DDD」を選んだ場合、D3に「1001、1002」のドロップダウンが表示され、 いずれかを選択します。 このような入力規制を設定したいのですが、 B3、C3、D3をどのように設定したらよいのか教えて下さい。 宜しくお願いいたします。

  • hee1
  • お礼率32% (137/422)

質問者が選んだベストアンサー

  • ベストアンサー
  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.9

#1、2、4、6、7、8、cjです。 #8補足欄へのレスです。 言われてみれば、別シートにある方が自然ですよね。 対応が遅れた感はあります。 変更点を■■で示しました。 入力規則設置するシートのシートモジュール、 まるまる差し替え、です。 ' ' ============================== Option Explicit ' ' ------------------------------ Const イベント範囲 As String = "C9:D20"  '  下位の入力規則を変更するイベント処理対象範囲の参照(2列)■要指定 Const マスタシート名 As String = "Sheet1"  '  マスタテーブルのシート名■■要指定 Const マスタ左上 As String = "V9"  '  マスタテーブル範囲の参照(データ部左上の単セル)■要指定         ' ' ユーザー設定 ↑ ' ' ------------------------------         ' ' 固定 ↓ Const SHOGE As String = "分類" Const SCOMMA As String = ","             ' ' 参照設定する場合◆ : Microsoft Scripting Runtime Private oDict(0 To 2) As Object  '  As Scripting.Dictionary ' ◆ ' ' ------------------------------ Sub 初期設定()  '  マスタ変更時の更新も   Call SetValid End Sub ' ' ------------------------------ Private Sub SetValid(Optional ByVal Target As Range)   Dim sKey As String   Dim sList As String   Dim nFldPos As Long   Dim nOffset As Long   Dim i As Long   If Target Is Nothing Then     Set Target = Range(イベント範囲)     sKey = SHOGE  '  "分類" '    nFldPos = 0& : nOffset = 0&     Range(イベント範囲)(1).Select ' ' ●●   Else     sKey = Target.Value     nFldPos = Target.Column - Range(イベント範囲).Column + 1     nOffset = 1&   End If   Application.EnableEvents = False   On Error GoTo Exit_   If oDict(0) Is Nothing Then Call SetDict   With Target     For i = nFldPos To 2       nOffset = nOffset + 1&       sList = oDict(i)(sKey)  '  ",A,B,C"  ",DDD,EEE,FFF"  ",1001,1002" If sList = "" Then ' ' ● MsgBox Split("分類: 品名:")(i) & sKey & " マッチしません" ' ' ● Application.EnableEvents = True ' ' ● Exit Sub ' ' ● End If ' ' ●       With .Columns(nOffset)         With .Validation           .Delete           .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=sList '          .IgnoreBlank = True '          .InCellDropdown = True         End With         sKey = Split(sList, SCOMMA)(1)  '  "A"  "DDD"  "1001"         .Value = sKey       End With     Next i   End With Exit_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbExclamation End Sub ' ' ------------------------------ Private Sub SetDict()   Dim mtxT()   Dim i As Long '  With Range(マスタ左上)  '  (1/2択)マスタが同一シート上にある場合■■要指定   With Sheets(マスタシート名).Range(マスタ左上)  '  (2/2択)マスタシート名を指定する場合■■要指定     mtxT = .Resize(.End(xlDown).Row - .Row + 1, 3).Value   End With     For i = 0 To 2     Set oDict(i) = CreateObject("Scripting.Dictionary") '    Set oDict(i) = New Scripting.Dictionary ' ◆   Next i   For i = 1 To UBound(mtxT)     If Not oDict(1).Exists(mtxT(i, 1)) Then       oDict(0)(SHOGE) = oDict(0)(SHOGE) & SCOMMA & mtxT(i, 1)       oDict(1)(CStr(mtxT(i, 1))) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2) ' ' ▲     ElseIf Not oDict(2).Exists(mtxT(i, 2)) Then       oDict(1)(CStr(mtxT(i, 1))) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2) ' ' ▲     End If     oDict(2)(CStr(mtxT(i, 2))) = oDict(2)(mtxT(i, 2)) & SCOMMA & mtxT(i, 3) ' ' ▲   Next i   Erase mtxT() '' ' ツリー確認用コード '  Dim k1, k2, s2, v0, v1 '  Debug.Print SHOGE, oDict(0)(SHOGE) '  k1 = oDict(1).Keys '  For Each v0 In k1 '    Debug.Print , v0, oDict(1)(v0) '    k2 = Split(oDict(1)(v0), SCOMMA) '    For Each v1 In k2 '      If v1 <> "" Then Debug.Print , , v1, oDict(2)(v1) '    Next '  Next End Sub ' ' ------------------------------ Private Sub Worksheet_Change(ByVal Target As Range)   If Target.Count > 1 Then Exit Sub   If Target.Value = "" Then Exit Sub   If Intersect(Range(イベント範囲).Resize(, 2), Target) Is Nothing Then Exit Sub   Call SetValid(Target) End Sub ' ' ------------------------------ Private Sub Worksheet_Deactivate()   Erase oDict() End Sub ' ' ==============================

hee1
質問者

お礼

この度は、いろいろと希望に対応下さいましたおかげで、 大変使いやすい表が出来上がりました。 また、カスタマイズしたい部分はありますが、 今回とは別に質問を上げたいと思います。 本当にお世話になりました。

その他の回答 (8)

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.8

#1、2、4、6、7、cjです。 #7補足欄へのレスです。 > こちらを実行して、リストから選択いたしますと、 > 「1004アプリケーション定義またはオブジェクト定義のエラーです」となります。 > (ただ、アラートが表示されますが処理は正常に行われているようなのです)。 エラーが起こるとすれば、正常終了ではなく 下位の入力規則が設定される前に終了してしまう筈なのですが。 、、という前提で対策を考えてみました。 > ...マスターテーブルの値ですが、... > 実値は、分類に全角文字で学校の名前(○○小学校)などが、 > 品名も全角文字で商品の名前(○○学生服)などが、 > 品番は、全角文字と半角英数字(GSW100EW)などが使われています。 > このあたりの固定をしないといけないのでしょうか。 文字列であれば、まず問題ないです。 特に説明しませんでしたが、入力規則のリスト指定がカンマ区切りですので、 分類、品名、品番、に指定する各セル値に","を使うことはエラーの原因になります。 また、数値や日付値を指定してある場合もエラーに繋がります。 以上の点は意識はしていたものの分類、品名、品番、という項目名からして 対策の必要ないと考えたものです。 でもまぁ数値については、対応しないのも変でしたね。バグ、と呼べなくもない。 セル値が数値でもエラーにならないようにしました。 ' ' ▲ 自分なりに想定の幅を拡げ、十分な対策を施したつもりではいますが、 私の迂闊は珍しくもないので、もし漏れがある場合に 原因を特定する為だけの一時的な(不要になったら削除する)記述を 5行 ' ● マークを付けて示しました。 マクロ側でDictionaryオブジェクトに登録したKeyと セル値とのマッチングがうまく行ってない場合にメッセージを表示しますので 表示されたなら、内容を確認してみてください。それによって対処します。 暫く様子みてみましょう。 > あと、処理後、C9のセルに戻りたいのですが > Range("C9").Select を どこに入れたら良いでしょうか。 追加した記述を ' ' ●● マークを付けて示しました。 処理後、というのが微妙ですが、初期設定後、という解釈です。 > 何度も申し訳ございません。 いいえ。お気になさらず。お互い様です。 こちらも即応レスはできませんが、何とか解決させたいです。 文字数制限に掛かることもあって、ご面倒でしょうが 2つのプロシージャだけ#7について差し換えでお願いします。 ' ' ------------------------------ Private Sub SetValid(Optional ByVal Target As Range)   Dim sKey As String   Dim sList As String   Dim nFldPos As Long   Dim nOffset As Long   Dim i As Long   If Target Is Nothing Then     Set Target = Range(イベント範囲)     sKey = SHOGE  '  "分類" '    nFldPos = 0& : nOffset = 0&     Range(イベント範囲)(1).Select ' ' ●●   Else     sKey = Target.Value     nFldPos = Target.Column - Range(イベント範囲).Column + 1     nOffset = 1&   End If   Application.EnableEvents = False   On Error GoTo Exit_   If oDict(0) Is Nothing Then Call SetDict   With Target     For i = nFldPos To 2       nOffset = nOffset + 1&       sList = oDict(i)(sKey)  '  ",A,B,C"  ",DDD,EEE,FFF"  ",1001,1002" If sList = "" Then ' ' ● MsgBox Split("分類: 品名:")(i) & sKey & " マッチしません" ' ' ● Application.EnableEvents = True ' ' ● Exit Sub ' ' ● End If ' ' ●       With .Columns(nOffset)         With .Validation           .Delete           .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=sList '          .IgnoreBlank = True '          .InCellDropdown = True         End With         sKey = Split(sList, SCOMMA)(1)  '  "A"  "DDD"  "1001"         .Value = sKey       End With     Next i   End With Exit_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbExclamation End Sub ' ' ------------------------------ Private Sub SetDict()   Dim mtxT()   Dim i As Long   With Range(マスタ左上)     mtxT = .Resize(.End(xlDown).Row - .Row + 1, 3).Value   End With      For i = 0 To 2     Set oDict(i) = CreateObject("Scripting.Dictionary") '    Set oDict(i) = New Scripting.Dictionary ' ◆   Next i   For i = 1 To UBound(mtxT)     If Not oDict(1).Exists(mtxT(i, 1)) Then       oDict(0)(SHOGE) = oDict(0)(SHOGE) & SCOMMA & mtxT(i, 1)       oDict(1)(CStr(mtxT(i, 1))) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2) ' ' ▲     ElseIf Not oDict(2).Exists(mtxT(i, 2)) Then       oDict(1)(CStr(mtxT(i, 1))) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2) ' ' ▲     End If     oDict(2)(CStr(mtxT(i, 2))) = oDict(2)(mtxT(i, 2)) & SCOMMA & mtxT(i, 3) ' ' ▲   Next i   Erase mtxT() '' ' ツリー確認用コード '  Dim k1, k2, s2, v0, v1 '  Debug.Print SHOGE, oDict(0)(SHOGE) '  k1 = oDict(1).Keys '  For Each v0 In k1 '    Debug.Print , v0, oDict(1)(v0) '    k2 = Split(oDict(1)(v0), SCOMMA) '    For Each v1 In k2 '      Debug.Print , , v1, oDict(2)(v1) '    Next '  Next End Sub ' ' ------------------------------

hee1
質問者

補足

毎回、迅速かつ正確なご回答に感謝申し上げます。 上記も大変上手く行きました。 ただ、大変申し訳ないのですが、 マスターテーブルの部分を別のシートに設置した場合は、 どうしたらよいでしょうか。 Const マスタ左上 As String = "Sheet1!V9" としても、ダメでした。 最後にこの部分を教えて頂ければ幸いです。 宜しくお願いいたします。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.7

こんにちは。#1、2、4、6、cjです。 #6で触れていた > ...セル範囲の参照を容易に変更できる内容に書き換え... やってみました。 その影響で処理の効率が落ちる面もあるので、その分、 他の部分を見直して補い、トータルでは、前より動作が軽くなっています。 先頭の2カ所だけ、セル範囲を指定すれば、 テーブルの位置を変更した場合にも容易に対応できます。 動作仕様はこれまで提示したものとまったく同じです。 まるまる差し替えで使ってください。 それでは、また。 ' ' ============================== Option Explicit ' ' ------------------------------ Const イベント範囲 As String = "C9:D20"  '  下位の入力規則を変更するイベント処理対象範囲の参照(2列)■要指定 Const マスタ左上 As String = "V9"  '  マスタテーブル範囲の参照(データ部左上の単セル)■要指定         ' ' ユーザー設定 ↑ ' ' ------------------------------         ' ' 固定 ↓ Const SHOGE As String = "分類" Const SCOMMA As String = ","             ' ' 参照設定する場合◆ : Microsoft Scripting Runtime Private oDict(0 To 2) As Object  '  As Scripting.Dictionary ' ◆ ' ' ------------------------------ Sub 初期設定()   Call SetValid End Sub ' ' ------------------------------ Private Sub SetValid(Optional ByVal Target As Range)   Dim sKey As String   Dim sList As String   Dim nFldPos As Long   Dim nOffset As Long   Dim i As Long   If Target Is Nothing Then     Set Target = Range(イベント範囲)     sKey = SHOGE  '  "分類" '    nFldPos = 0& : nOffset = 0&   Else     sKey = Target.Value     nFldPos = Target.Column - Range(イベント範囲).Column + 1     nOffset = 1&   End If   Application.EnableEvents = False   On Error GoTo Exit_   If oDict(0) Is Nothing Then Call SetDict   With Target     For i = nFldPos To 2       nOffset = nOffset + 1&       sList = oDict(i)(sKey)  '  ",A,B,C"  ",DDD,EEE,FFF"  ",1001,1002"       With .Columns(nOffset)         With .Validation           .Delete           .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=sList '          .IgnoreBlank = True '          .InCellDropdown = True         End With         sKey = Split(sList, SCOMMA)(1)  '  "A"  "DDD"  "1001"         .Value = sKey       End With     Next i   End With Exit_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbExclamation End Sub ' ' ------------------------------ Private Sub SetDict()   Dim mtxT()   Dim i As Long   With Range(マスタ左上)     mtxT = .Resize(.End(xlDown).Row - .Row + 1, 3).Value   End With      For i = 0 To 2     Set oDict(i) = CreateObject("Scripting.Dictionary") '    Set oDict(i) = New Scripting.Dictionary ' ◆   Next i   For i = 1 To UBound(mtxT)     If Not oDict(1).Exists(mtxT(i, 1)) Then       oDict(0)(SHOGE) = oDict(0)(SHOGE) & SCOMMA & mtxT(i, 1)       oDict(1)(mtxT(i, 1)) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2)     ElseIf Not oDict(2).Exists(mtxT(i, 2)) Then       oDict(1)(mtxT(i, 1)) = oDict(1)(mtxT(i, 1)) & SCOMMA & mtxT(i, 2)     End If     oDict(2)(mtxT(i, 2)) = oDict(2)(mtxT(i, 2)) & SCOMMA & mtxT(i, 3)   Next i   Erase mtxT() '' ' < ツリー確認用 '  Dim k1, k2, s2, v0, v1 '  Debug.Print SHOGE, oDict(0)(SHOGE) '  k1 = oDict(1).Keys 'Split(SHOGE, SCOMMA) '  For Each v0 In k1 '    Debug.Print , v0, oDict(1)(v0) '    k2 = Split(oDict(1)(v0), SCOMMA) '    For Each v1 In k2 '      Debug.Print , , v1, oDict(2)(v1) '    Next '  Next '' ' > End Sub ' ' ------------------------------ Private Sub Worksheet_Change(ByVal Target As Range)   If Target.Count > 1 Then Exit Sub   If Target.Value = "" Then Exit Sub   If Intersect(Range(イベント範囲).Resize(, 2), Target) Is Nothing Then Exit Sub   Call SetValid(Target) End Sub ' ' ------------------------------ Private Sub Worksheet_Deactivate()   Erase oDict() End Sub ' ' ==============================

hee1
質問者

補足

改訂頂きましてありがとうございます。 #6の方でも、上手く行きました。 確かに、イベント処理対象範囲が変わる可能性が有り、 こちらの改訂版を使えればと思ったのですが、 こちらを実行して、リストから選択いたしますと、 「1004アプリケーション定義またはオブジェクト定義のエラーです」となります。 (ただ、アラートが表示されますが処理は正常に行われているようなのです)。 なお、マスターテーブルの値ですが、質問の際 便宜上、A、DDDD、1001、などといたしましたが、 実値は、分類に全角文字で学校の名前(○○小学校)などが、 品名も全角文字で商品の名前(○○学生服)などが、 品番は、全角文字と半角英数字(GSW100EW)などが使われています。 このあたりの固定をしないといけないのでしょうか。 あと、処理後、C9のセルに戻りたいのですが Range("C9").Select を どこに入れたら良いでしょうか。 何度も申し訳ございません。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.6

#1、2、4、cjです。 #4補足欄へのレスです。 > B3の部分が C9に、 > G3の部分が V9に移動しました。 都合8カ所、セル範囲の参照を直す必要があります。  変更前の記述を先頭に「'」を付けてコメントブロック、  変更後の記述を直下の行に、 示しました。 シートモジュールごと、まるまる、差し替えれば、 移動後の各テーブルに対応しています。 今後も変更の可能性があるならば、 セル範囲の参照を容易に変更できる内容に書き換えた方が いいのかな?と思っています。 一方で、"マスター"を移動する機会は殆どないだろう、という 都合のいい予想もあるので、今回は、 対症療法的な修正だけにとどめます。 (あまりレスが増えても混乱してしまうでしょうし) もし、今後も移動することが想定されるならば、 少しでもメンテし易いものに書き直そうと思います。 その場合は、改めて、別件の質問として来週ぐらいにでも あげてみてください。 設計の異なるアプローチや色んな仕様を試しているうちに 手元では、15バージョン程になってしまい、 混乱している上に、今、私の頭のパフォーマンスが落ちています。 少し時間を空けて欲しいのは、そういう理由です。 やる気はありますので(笑) では、修正済のコードを。 Option Explicit Private oDict As Object ' ' ------------------------------ Private Sub Worksheet_Change(ByVal Target As Range)   If Target.Count > 1 Then Exit Sub   If Target.Value = "" Then Exit Sub '  If Target.Row < 3 Or Target.Row > 14 Then Exit Sub   If Target.Row < 9 Or Target.Row > 20 Then Exit Sub '  If Target.Column > 3 Or Target.Column = 1 Then Exit Sub   If Target.Column > 4 Or Target.Column < 3 Then Exit Sub   Application.EnableEvents = False   On Error GoTo Exit_   Call UniqValid品名品番(Target) Exit_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbExclamation End Sub ' ' ------------------------------ Sub UniqValid品名品番(ByVal Target As Range)   Dim mtxSrc, arrList   Dim sParent As String   Dim i As Long   Dim flg As Boolean '  mtxSrc = Range(Cells(3, Target.Column + 5), Cells(3, Target.Column + 6).End(xlDown)).Value   mtxSrc = Range(Cells(9, Target.Column + 19), Cells(9, Target.Column + 20).End(xlDown)).Value   sParent = Target.Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   For i = 1 To UBound(mtxSrc)     If mtxSrc(i, 1) = sParent Then       oDict(mtxSrc(i, 2)) = Empty       flg = True     ElseIf flg Then       Exit For     End If   Next i   arrList = oDict.keys   With Target.Offset(, 1)     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With '  If Target.Column = 2 Then Call UniqValid品名品番(Target.Offset(, 1))   If Target.Column = 3 Then Call UniqValid品名品番(Target.Offset(, 1))   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------ Sub UniqValid分類_開始()   Dim vSrc, v, arrList '  vSrc = Range("G3", Range("G3").End(xlDown)).Value   vSrc = Range("V9", Range("V9").End(xlDown)).Value   If UBound(vSrc) < 1 Then Exit Sub   Set oDict = CreateObject("Scripting.Dictionary")   For Each v In vSrc     oDict(v) = Empty   Next   arrList = oDict.keys   Application.EnableEvents = False '  With Range("B3")   With Range("C9")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = arrList(0)   End With '  Call UniqValid品名品番(Range("B3"))   Call UniqValid品名品番(Range("C9")) '  Range("B3:E3").Copy Destination:=Range("B4:B14")   Range("C9:F9").Copy Destination:=Range("C10:C20")   Application.EnableEvents = True End Sub ' ' ------------------------------

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.5

No.3です! たびたびごめんなさい。 前回の投稿でSheet2のA~C列の名前定義はしなくても大丈夫のようです。 すなわち前回アップした画像では Sheet2のA1~C1セルのアンダースコア-は必要なく、 そのまま「分類」名を入力しておけば 対応できそうです。 Sheet1のB列の入力規則の「元の値」の欄に =Sheet2!A$1:C$1 という数式を入れるだけで対応できます。 ただし、D列以降はやはり名前定義が必要みたいですね! 実際にExcel2007でOFFSET関数でやってみると やはり別Sheetは参照できないようですので、前回同様名前定義しなくてはならないようです。 ※Excel2010以降であれば名前定義は必要なく、表さえ作成しておけば 元の値の欄に数式を入れるだけで対応できます。 ちゃんと検証せずに投稿してごめんなさいね。m(_ _)m

hee1
質問者

お礼

おかげさまで、 いろいろな方法が確認できました。 今回は、VBAであっさりとできてしまい (VBAを組んで下さった方は大変だったはず) こちらを使わせて頂くこととしました。 ありがとうございました。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.4

#1、2、cjです。 すみません。#2で、一部ミス(慌てて転載ミス)があって 機能しないものを掲載していました。 Sub UniqValid分類_開始() だけ、まるまる差し替えてくださいませ。 失礼しました。 ' ' ------------------------------ Sub UniqValid分類_開始()   Dim vSrc, v, arrList   vSrc = Range("G3", Range("G3").End(xlDown)).Value   If UBound(vSrc) < 1 Then Exit Sub   Set oDict = CreateObject("Scripting.Dictionary")   For Each v In vSrc     oDict(v) = Empty   Next   arrList = oDict.keys   Application.EnableEvents = False   With Range("B3")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = arrList(0)   End With   Call UniqValid品名品番(Range("B3"))   Range("B3:E3").Copy Destination:=Range("B4:B14")   Application.EnableEvents = True End Sub ' ' ------------------------------

hee1
質問者

補足

早速補足下さいましてありがとうございます。 差し替えまして上手く行きました。 もう一点だけ教えて下さい。 実際の票に配置したときに、 B3の部分が C9に、 G3の部分が V9に移動しました。 このとき、Sub UniqValid分類_開始() の Rangeで指定された部分を該当セルに書き換え 以下の通りにしました。 ' ' ------------------------------ Sub UniqValid分類_開始() Dim vSrc, v, arrList vSrc = Range("V9", Range("V9").End(xlDown)).Value If UBound(vSrc) < 1 Then Exit Sub Set oDict = CreateObject("Scripting.Dictionary") For Each v In vSrc oDict(v) = Empty Next arrList = oDict.keys Application.EnableEvents = False With Range("C9") With .Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _ Operator:=xlBetween, Formula1:=Join(arrList, ",") End With .Value = arrList(0) End With Call UniqValid品名品番(Range("C9")) Range("C9:F9").Copy Destination:=Range("C10:C20") Application.EnableEvents = True End Sub ' ' ------------------------------ しかし、これを実行すると、「400」とだけかかれたアラートが出ます。 こんな、単純な対応ではダメでしょうか・・・ この部分だけ、今一度お願いいたします。

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.3

こんばんは! 超ベタな方法ですが・・・ やり方だけを↓の画像で説明します。(画像が小さかったら拡大してください。) 画像の上側をSheet2・下の右側をSheet3とし、下側左のSheet1にリスト表示させるとします。 表の作成と名前定義に一手間、いや二手間以上しっかり手間をかけます。 画像では頭の分類がアルファベットになっていますね!(実際はアルファベットではないと思いますが) 名前定義する際に数字およびアルファベットの中で使えないものがありますので、 あらかじめアンダースコアー(_)を付けたデータで表を作成しておきます。 (分類名が数値・アルファベット以外であれば頭のアンダースコアーは必要ありません。) (1)Sheet2のA1~C1セルを範囲指定 → 名前ボックスに 仮に 分類 と入力 → Enter これでSheet2のA1~C1セルが「分類」という名前定義されました。 (2)Sheet2のA1以降を範囲指定 → 数式 → 名前の管理 → 選択範囲から作成 → 上端行 → OK B1以降を範囲指定 → ・・・中略・・・(同様に) → OK この操作をSheet2のすべての列で行います。 これでSheet2の色付きセルで名前定義されます。 (3)Sheet3に分類・品名・品番のすべてをアンダースコアーでつないだデータの価格を作成します。 以上の準備ができれば後は簡単です。 Sheet1のB3以降を範囲指定 → データ → データの入力規則 → リスト → 元の値の欄に =分類 としてOK   C3以降を範囲指定 → (同上)・・・中略・・・ → 元の値の欄に =INDIRECT(B3) としてOK D3以降を範囲指定 → (同上)・・・中略・・・ → 元の値の欄に =INDIRECT(B3&"_"&C3) としてOK これで入力規則の設定は完了です。 最後にE3セルに =IF(COUNTBLANK(B3:D3),"",IFERROR(VLOOKUP(B3&"_"&C3&"_"&D3,Sheet3!A:B,2,0),"該当データなし")) という数式を入れオートフィルで下へコピーしておきます。 これで何とかご希望に近い形にならないでしょうか? ※ Exce2010以降であればリストの元の値の欄に数式で別Sheetを指定できますが、 Excel2007ではおそらくダメだったと思います。 そのためこまめに名前定義してみました。 他に良い方法があればごめんなさいね。m(_ _)m

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.2

#1、cjです。 #!補足欄へのレスです。 今あまり時間取れないので取り急ぎ。 扱いは全く同じです。まるごと差し換えで。 プロシージャ、ひとつ減らしました。 それと、ひとつだけ注意点。 '子'リストの自動変更は、B3:C14の範囲内で 単一のセルの値変更があった場合にのみ機能します。 例えば、B3:C14の範囲内の複数セル範囲へ貼り付けした場合などは '子'リストの自動変更は行われない仕様です。 この点の仕様変更が必要なら再レスします。 ただ、次は明日になると思います(今から送別会で遅くなるので)。 ' ' ------------------------------ Option Explicit Private oDict As Object ' ' ------------------------------ Private Sub Worksheet_Change(ByVal Target As Range)   If Target.Count > 1 Then Exit Sub   If Target.Value = "" Then Exit Sub   If Target.Row < 3 Or Target.Row > 14 Then Exit Sub   If Target.Column > 3 Or Target.Column = 1 Then Exit Sub   Application.EnableEvents = False   On Error GoTo Exit_   Call UniqValid品名品番(Target) Exit_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbCritical End Sub ' ' ------------------------------ Sub UniqValid品名品番(ByVal Target As Range)   Dim mtxSrc, arrList   Dim sParent As String   Dim i As Long   Dim flg As Boolean   mtxSrc = Range(Cells(3, Target.Column + 5), Cells(3, Target.Column + 6).End(xlDown)).Value   sParent = Target.Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   For i = 1 To UBound(mtxSrc)     If mtxSrc(i, 1) = sParent Then       oDict(mtxSrc(i, 2)) = Empty       flg = True     ElseIf flg Then       Exit For     End If   Next i   arrList = oDict.keys   With Target.Offset(, 1)     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With   If Target.Column = 2 Then Call UniqValid品名品番(Target.Offset(, 1))   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------ Sub UniqValid分類_開始()   Dim vSrc, v, arrList   vSrc = Range("G3", Range("G3").End(xlDown)).Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   If UBound(vSrc) < 1 Then     oDict.Add v, Empty   Else     For Each v In vSrc       oDict(v) = Empty     Next   End If   arrList = oDict.keys   Application.EnableEvents = False   With Range("B3")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With   Call UniqValid品名((arrList(0)))      Range("B3:E3").Copy Destination:=Range("B4:B14")      Application.EnableEvents = True   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.1

こんにちは。 VBAによる対応になります。 Sub UniqVal分類_開始() を実行することで初期設定されます。 [分類]を追加|削除した場合は初期設定し直す必要があります。 後は、B3,C3が変更される度に下位のリストを自動的に変更します。 [分類]>[品名]>[品番] '親'側が変更されると、'子'('孫')のリストも変更され、 それぞれ、リストの最上位にある値を仮設定します。 Worksheet_Change イベントを既に使っている場合は 適切な形で組み込み統合する必要があります。 (手に余るようでしたら、既存のコードをご提示の上、ご相談ください) 当該シートのシートモジュールに、 以下、全文、過不足なく、貼付け、Sub UniqVal分類_開始()を実行、保存。 Option Explicit ' ' ------------------------------ Private oDict As Object ' ' ------------------------------ Private Sub Worksheet_Change(ByVal Target As Range)   If Target.Count > 1 Then Exit Sub   If Target.Value = "" Then Exit Sub   If Target.Row <> 3 Then Exit Sub '  If Target.Column > 3 Or Target.Column = 1 Then Exit Sub   If Not Target.Column Like "[23]" Then Exit Sub   Application.EnableEvents = False   On Error GoTo ErrOut_   Select Case Target.Column   Case 2     Call UniqVal品名(Target.Value)   Case 3     Call UniqVal品番(Target.Value)   End Select ErrOut_:   Application.EnableEvents = True   If Err Then MsgBox Err & Err.Description, vbCritical End Sub ' ' ------------------------------ Sub UniqVal品番(sParent As String)   Dim mtxSrc, arrList   Dim i As Long   Dim flg As Boolean   mtxSrc = Range("H3", Range("I3").End(xlDown)).Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   For i = 1 To UBound(mtxSrc)     If mtxSrc(i, 1) = sParent Then       oDict(mtxSrc(i, 2)) = Empty       flg = True     ElseIf flg Then       Exit For     End If   Next i   arrList = oDict.keys   With Range("D3")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------ Sub UniqVal品名(sParent As String)   Dim mtxSrc, arrList   Dim i As Long   Dim flg As Boolean   mtxSrc = Range("G3", Range("H3").End(xlDown)).Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   For i = 1 To UBound(mtxSrc)     If mtxSrc(i, 1) = sParent Then       oDict(mtxSrc(i, 2)) = Empty       flg = True     ElseIf flg Then       Exit For     End If   Next i   arrList = oDict.keys   With Range("C3")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With   Call UniqVal品番((arrList(0)))   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------ Sub UniqVal分類_開始()   Dim vSrc, v, arrList   vSrc = Range("G3", Range("G3").End(xlDown)).Value   On Error GoTo CrDict_   oDict.RemoveAll   On Error GoTo 0   If UBound(vSrc) < 1 Then     oDict.Add v, Empty   Else     For Each v In vSrc       oDict(v) = Empty     Next   End If   arrList = oDict.keys   Application.EnableEvents = False   With Range("B3")     With .Validation       .Delete       .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _             Operator:=xlBetween, Formula1:=Join(arrList, ",")     End With     .Value = (arrList(0))   End With   Call UniqVal品名((arrList(0)))   Application.EnableEvents = True   Exit Sub CrDict_:   Set oDict = CreateObject("Scripting.Dictionary")   Resume End Sub ' ' ------------------------------

hee1
質問者

補足

早速のご回答感謝申し上げます。 大変上手く行きました。 ただ、質問のしかたが悪く申し訳ないのですが、 B3:E3の処理を、12行(B14:E14まで)行いたかったのですが、 この場合、単純にセルをコピーしても上手く行きませんでした。 VBAの知識がなく、自分で修正することができません。 補足頂けましたら幸いです。

関連するQ&A

  • エクセル2007 ドロップダウンリスト

    vista利用の初心者です。 よろしくお願いします。 ドロップダウンリストで選択した後(後という表現が適切かどうかわかりませんが)の 計算式をご存じの方は教えてください。 たとえば  A1に5と入力しておきます。 B1にドロップダウンリストで あ50,い60,う65と設定しておきます。 C1には ドロップダウンリストであ50を選択した場合は A1の5×50の数値 い60選択で 5×60 ・・・の数値を設定したいと思っています。 どなたか詳しい方、よろしくお願い申し上げます。

  • エクセルのドロップダウンリスト

    エクセルのドロップダウンリストについて、困っていることがあります。 たとえば、 ・Aシート A列|B列|C列 1|ペン|200 2|鉛筆|100 3|本|200 ・Bシート A列|B列 ペン(ドロップダウンリスト)|200 という風に、Bシートのドロップダウンリストを選択すると、動的に200と隣のセル(B列)に表示するようにするにはどのようにすればいいでしょうか? よろしくお願いします。

  • ドロップダウンリストの連動した使い方

    ドロップダウンリスト同士を連動させたいのですが、例えば、カラムA,B,Cにそれぞれドロップダウンリストを作成しておき、カラムAでドロップダウンリストより任意の値を選ぶと、自動的にカラムB,Cも同じ位置の値がセットされるようにしたいのです。同じ位置の意味は、A,B,Cのドロップダウンリストの値を仮に10個設定しておいたら、カラムAで上から3番目を選んだらカラムB,Cでも上から3番目が選ばれセットされるようにしたいのです。 よろしくお願いします。

  • ドロップダウンリストとIF関数

    ドロップダウンリストから選択すると指定の数値を出したいのですが、IFを複数設定するにはどうすればよいでしょうか?リストから「A」を表示すると同じシート内の別の場所に「1」、「B」ならば「2」と表示させたいです。「=IF(A1=B1,C1)」の式でひとつは可能なのですが複数ある場合の方法が分からないので教えて下さい。

  • エクセルでのドロップダウンリスト作成について

    エクセルで、3つの項目(A,B,Cとします)をドロップダウンリストから選択する場合、A,B,Cを『名前の定義』で関連付けることはできました。しかし、A,B,Cが同じ文字列の場合、同シート上で同じ名前の定義にできないため、ドロップダウンリストが作成できずにいます。 このようなドロップダウンリストを作成するにはどのようにすれば良いか教えてください。 VBAなどが必要になるのでしょうか? 宜しくお願いします。

  • 【Excel】シート上のドロップダウンリストから検索するには

    教えてください! ドロップダウンリストをsheet1にフォームツールバーから描きます。 その右側に同じフォームよりボタンを描き「検索」ボタンとします。 ドロップダウンリストにはsheet2のA1:A5を表示させます。 ドロップダウンリストでA1を選択し、検索ボタンを押すと sheet3のA1を表示させる記述はどうなるのでしょうか? A1だけではなくA2・A3・A4を選択し、検索ボタンを押すと A2はsheet4、A3はsheet5という風に表示させたいのです。 よろしくお願いします。

  • ドロップダウンリストを大きくしたい。

    エクセル2000です。 入力規制でドロップダウンリストからの選択で入力しています。 リストデータが30件あったとして、ドロップダウンリスト内にその30件一度に表示させることはできないでしょうか?(10件程度しか表示されず、スクロールさせています) または、表示件数を増やすような設定は、ないでしょうか?

  • [Excel]で連動するドロップダウンリストを作りたい

    Excel2007、もしくは2003を使い、連動するドロップダウンリストを作りたいのですが、上手くいきません。 1個目のドロップダウンでA部を選ぶと2個目のドロップダウンでA,B,C担当を選ばせるようにするというのは、A,B,C担当をA部の名前で定義し、入力規制ダイアログの元の値に、INDEIRECT関数を使うことで解決するかと思います。 ですが、たとえば最初に県を選ばせ、それぞれの県にA部が存在し、ある県のA部にはA担当とC担当、ある県のA部にはB担当とC担当、というように3階層以上で、途中の階層で名前が重複していおり、なおかつその下の階層はそれぞれ違う場合はINIRECTでは上手くいきません。 A部の名前で定義してしまうと、どの県を選んでも全部の担当が出てしまいますし…。 何か良い方法をご存知の方がいらっしゃったら、どうか知恵をお貸しください。

  • ドロップダウンリストの連動

    いつも大変お世話になっております。 エクセルで、セルO6にA社とB社を名前の定義で登録しドロップダウンリストで選択できるようにしました。 セルD14に、セルO6でA社を選択した場合には、A5052(H)とA5052(R)がドロップダウンリストで選択でき、同じく、セル14に、セルO6でB社を選択した場合には、アルハイスとアルジェイドがドロップダウンリストで選択できるようにしたいです。 こちらで拝見したり、ネットで調べたのですが、列が同じの場合はやれそうでしたが、同列以外ではできませんでしょうか? (INDIRECTや、ドロップダウンリストを使用してやったりできるのでしょうか) 説明が上手く出来ず申し訳ありません。 ご教授して頂けたらありがたいです。 よろしくお願いします。

  • Excel2010、ドロップダウンリストの問題

    Excel2010のドロップダウンリストについて、もとのリストが編集できず困っています。(実は電話で、そのような相談を受けているのですが) 「校閲」→「入力規則」で設定する画面がありますが、 ここで、「データの入力規則」の「設定」タブで、入力値の種類→「リスト」とし、元の値のところ、ここが「空欄」になっているようです。 にもかかわらず、 その指定のセルはドロップダウンが使えて、リストがちゃんと出てくるようです。 他の情報としては、 ・ドロップダウンのセルの右に出てくる三角マークが表示されない。(本当はドロップダウンを使っていないのではないか、という疑念。あるいは単に表示されない設定にしているだけかもしれません。VBAとか使っているのか) ・セルをクリックすると「ドロップダウンのリンクがなんとか・・」という表示とともに、「実際のリスト自体は表示され、使える」ようです。 ・目的としては、そのリスト自体を「編集」(修正)することです。 データを送ってもらえれば何らかの対処もあるかと思いますが、セキュリティ上の関係でできないようです。 何かヒントでも分かればお願いします。

専門家に質問してみよう