• 締切済み

エクセルマクロで入力規制(リスト)の作成

エクセルで発注書を作成しておりますが、商品名の入力での入力間違いを 防ぐ為、入力規制(リスト)を使用しようかと思っております。 しかしながら、商品台帳は別シート上で下記の通り定型フォームと なっており、発注書上の「大分類」「中分類」「小分類」入力箇所にて リスト形式で商品を絞っていく体裁にしたいと思っております。 大分類 中分類 小分類 家電 パソコン PC-JD777 家電 パソコン PC-JD999 家電 テレビ TV-32T 家電 テレビ TV-45J 家電 DVDプレーヤー 590DV 家電 DVDプレーヤー 620DV 日常雑貨 文房具 鉛筆 日常雑貨 文房具 消しゴム 日常雑貨 文房具 シャープペン 日常雑貨 台所用品 なべ 日常雑貨 台所用品 やかん 食品 野菜 にんじん 食品 野菜 キャベツ 食品 肉類 牛肉 食品 肉類 豚肉 エクセルの入力規制(リスト)での作成をいろいろ調べたのですが、 どうもよく分かりません。 マクロ・VBAでも構いませんので何卒宜しくお願いいたします。

みんなの回答

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.5

ANo3です。 補足ですが、大分類はブックを開いた時に設定する様になっておりますので、実行前にファイルを一旦閉じて開き直すか、VBEでSub Auto_Openを実行して下さい。 コードをすっきりさせようとトライしましたので、ご参考に添付します。 <標準モジュール> Public Enum classLevel major = 0 middle = 1 minor = 2 End Enum 'ファイルオープン時に大分類を設定 Sub auto_open() Call classification(classLevel.major) End Sub '各入力規則を設定する Sub classification(level As Long) Dim dbSheet As Worksheet Dim validationSheet As Worksheet Dim extractRange As Range Dim criteriaArea As Range Dim dataTable As Range Dim inputArea As Range Set dbSheet = ThisWorkbook.Sheets("DB") Set validationSheet = ThisWorkbook.Sheets("入力") Set dataTable = dbSheet.Range("$A$6").CurrentRegion Set criteriaArea = dbSheet.Range("$A$1:$B$2") Set inputArea = validationSheet.Range("$A$1:$C$2") If dbSheet.FilterMode = True Then dbSheet.ShowAllData Select Case level Case classLevel.major criteriaArea.Rows(2).Clear 'これを入れないとフィルターが誤動作 With dataTable.Columns(1) .AdvancedFilter Action:=xlFilterInPlace, Unique:=True Set extractRange = .SpecialCells(xlCellTypeVisible) End With inputArea.Rows(2).Clear Call setValidation(inputArea.Cells(2, 1), validationString(extractRange)) Case classLevel.middle criteriaArea.Cells(2, 1).Value = inputArea.Cells(2, 1) With dataTable.Columns("A:B") .AdvancedFilter Action:=xlFilterInPlace, _ CriteriaRange:=criteriaArea.Columns(1), Unique:=True Set extractRange = Intersect(.SpecialCells(xlCellTypeVisible), .Columns(2)) End With inputArea.Range(Cells(2, 2), Cells(2, 3)).Clear Call setValidation(inputArea.Cells(2, 2), validationString(extractRange)) Case classLevel.minor criteriaArea.Cells(2, 2).Value = inputArea.Cells(2, 2) With dataTable .AdvancedFilter Action:=xlFilterInPlace, _ CriteriaRange:=criteriaArea, Unique:=True Set extractRange = Intersect(.SpecialCells(xlCellTypeVisible), .Columns(3)) End With inputArea.Cells(2, 3).Clear Call setValidation(inputArea.Cells(2, 3), validationString(extractRange)) End Select End Sub '非連続の範囲の値を、カンマ区切り文字列に統合する(先頭=フィールド名として除外する) Private Function validationString(extractRange As Range) Dim targetArea As Range Dim i As Long Dim fieldName As String fieldName = extractRange.Cells(1).Value For Each targetArea In extractRange.Areas For i = 1 To targetArea.Rows.Count If targetArea.Cells(i).Value <> fieldName Then If validationString = "" Then validationString = targetArea.Cells(i).Value Else validationString = validationString & "," & targetArea.Cells(i).Value End If End If Next i Next targetArea End Function '入力規則-リスト文字列・ドロップダウンを設定する Sub setValidation(targetRange As Range, validationString As String) With targetRange.Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _ xlBetween, Formula1:=validationString End With End Sub <入力シートモジュール> Private Sub Worksheet_Change(ByVal Target As Range) If Intersect(Target, Range("$a$2:$b$2")) Is Nothing Then Exit Sub Select Case Target.Address Case "$A$2" Call classification(classLevel.middle) Case "$B$2" Call classification(classLevel.minor) End Select End Sub

jsk_l
質問者

補足

敏速なご返答大変ありがとうございます! ご指摘いただいた通り、とんちんかんな事をしておりまして、標準モジュール に組み込みましたら、無事動きました! 本当にありがとうございました。 いただいたコードはまだ全て理解できてませんが、今回の例題として コツコツと解析し勉強させていただきます。その過程で、今回のVBAの 疑問点や不明点がありましたら、また補足質問させていただくかと 思いますが、気が向いた際で構いませんので宜しくお願いいたします。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.4

ANo3です。 >構文をDBシート、入力シートのモジュールに貼り付け、 >マクロを動かしてみたのですが、入力モジュールの5行目... とありますが、長い方のコードをもし、DBシートモジュールに貼り付けているなら、標準モジュールに貼り付けて下さい。 DBシートにはコードは記述しません。 ※VBEで挿入/標準モジュールを実行すると、Module1が生成されますので、そこに貼り付けて下さい。シートモジュールをご存じの方なら、お分かりだとは思いますが念のため。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.3

Accessだと沢山ヒットしますが、Excelは見つかりませんね。興味本位で作ってみました。セルの絶対指定を多用した融通の利かない、動けば良いというレベルのコードですが、何かの参考になれば幸いです。当方Excel2000です。複雑なので、環境が違って動かないケースのアドバイスはしかねます。綴りの間違いはご笑納下さい。 「DB」及び「入力」という名称のシートを用います。DBシートにデータを追加しても、そのままで動く仕様にしてあります。 "DB"シート フィルターオプションで絞り込みます ..............A..............B..............C 1..........大分類.......中分類.......小分類 2..........(自動で設定) 3~5行は空 6..........大分類.......中分類.......小分類 7..........家電........パソコン......PC-JD777 8..........家電........パソコン......PC-JD999 9..........家電........テレビ.......TV-32T 10..........家電........テレビ.......TV-45J 11..........家電........DVDプレーヤー..590DV 12..........家電........DVDプレーヤー..620DV 13..........日常雑貨......文房具.......鉛筆 14..........日常雑貨......文房具.......消しゴム 後略 "入力"シート A2→B2→C2の順に自動で入力規則を設定し、その中から選択できます(但しA2はファイルオープン時に設定) ..............A..............B..............C 1..........大分類.......中分類.......小分類 2.........(自動で入力規則-リストが設定される) <標準モジュール> Public Enum classLevel major = 0 middle = 1 minor = 2 End Enum 'ファイルオープン時に大分類を設定 Sub auto_open() Call classification(major) End Sub '各入力規則を設定する Sub classification(level As Long) Dim dbSheet As Worksheet Dim validationSheet As Worksheet Dim targetRange As Range Dim extractRange As Range Set dbSheet = ThisWorkbook.Sheets("DB") Set validationSheet = ThisWorkbook.Sheets("入力") If dbSheet.FilterMode = True Then dbSheet.ShowAllData Select Case level Case major dbSheet.Range("$A$2:$B$2").Clear Set targetRange = Intersect(dbSheet.Range("A6").CurrentRegion, dbSheet.Columns(1)) targetRange.AdvancedFilter Action:=xlFilterInPlace, Unique:=True Set extractRange = targetRange.SpecialCells(xlCellTypeVisible) validationSheet.Range("A2:C2").Clear Call setValidation(validationSheet.Range("A2"), validationString(extractRange)) Case middle dbSheet.Range("A2").Value = validationSheet.Range("A2") Set targetRange = Intersect(dbSheet.Range("A6").CurrentRegion, dbSheet.Columns("$A:$B")) targetRange.AdvancedFilter Action:=xlFilterInPlace, _ CriteriaRange:=dbSheet.Range("A1:A2"), Unique:=True Set extractRange = Intersect(targetRange.SpecialCells(xlCellTypeVisible), targetRange.Columns(2)) validationSheet.Range("B2:C2").Clear Call setValidation(validationSheet.Range("B2"), validationString(extractRange)) Case minor dbSheet.Range("B2").Value = validationSheet.Range("B2") Set targetRange = dbSheet.Range("A6").CurrentRegion targetRange.AdvancedFilter Action:=xlFilterInPlace, _ CriteriaRange:=dbSheet.Range("A1:B2"), Unique:=True Set extractRange = Intersect(targetRange.SpecialCells(xlCellTypeVisible), targetRange.Columns(3)) validationSheet.Range("C2").Clear Call setValidation(validationSheet.Range("C2"), validationString(extractRange)) End Select End Sub Private Function validationString(extractRange As Range) Dim targetArea As Range Dim i As Long Dim fieldName As String fieldName = extractRange.Cells(1).Value For Each targetArea In extractRange.Areas For i = 1 To targetArea.Rows.Count If targetArea.Cells(i).Value <> fieldName Then If validationString = "" Then validationString = targetArea.Cells(i).Value Else validationString = validationString & "," & targetArea.Cells(i).Value End If End If Next i Next targetArea End Function Sub setValidation(targetRange As Range, validationString As String) With targetRange.Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _ xlBetween, Formula1:=validationString .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .ErrorTitle = "" .InputMessage = "" .ErrorMessage = "" .IMEMode = xlIMEModeNoControl .ShowInput = True .ShowError = True End With End Sub <入力シートモジュール> Private Sub Worksheet_Change(ByVal Target As Range) If Intersect(Target, Range("$a$2:$b$2")) Is Nothing Then Exit Sub Select Case Target.Address Case "$A$2" Call classification(middle) Case "$B$2" Call classification(minor) End Select End Sub

jsk_l
質問者

補足

ご回答大変ありがとうございました! 親身に対応いただき大変感激しております。 VBAは最近始めたばかり、まだ手探り状態ですが参考にさせていただき、 勉強していきたいと思います。 ご回答いただいた構文をDBシート、入力シートのモジュールに貼り付け、 マクロを動かしてみたのですが、入力モジュールの5行目  「Call classification」が反転され、コンパイルエラー(Subまたは functionが定義されてません」と表示されます。そこでOKを押すと、 1行目の「Private Sub Worksheet_Change(ByVal Target As Range)」 が黄色に色づき、エラーとなります。 何分本当にまだ良く分からなくて、せっかくご教授いただいたのに、 うまく利用できません。 大変恐れ入りますが解決策や見当違いなことをやっているのであれば、 ご指摘いただけないでしょうか?どうぞ宜しくお願いいたします。

noname#79209
noname#79209
回答No.2

> 元データとなる商品リストは随時新商品が追加となっていく事、 > 元データはcsvデータであることから そうなるとやはり、VBA組むしかないですね。 ただ、リストの直接のもととなるデータ(大分類、中分類)は、 CSVから入ってきたシートでなく、別に用意したシートから持ってくるようにしておき、 そのシートに名前付けをしておき、CSVをと入り込む都度、リストデータを 作り出すようなVBAを組むことでしょうね。 Accessだともっと楽なんですけど... また、有償ですが、 http://www.civil-design.net/soft_ippan/kaisoulist/index.html 上記のようなものをみつけましたが、質問者さんの運用環境に合っているかどうか....

noname#79209
noname#79209
回答No.1

http://www.eurus.dti.ne.jp/~yoneyama/Excel/ex-q-a/index.html#nyuryoku の満赤あたりにある、「入力岐宿」が参考になりませんか? 「名前」の定義と組み合わせて使います。

jsk_l
質問者

補足

回答ありがとうございました。 しかしながら、例えば「大分類」でリスト化した場合、  家電  家電  家電  家電  日常雑貨  日常雑貨  日常雑貨 と同一名称が重複して表示されてしまいます。 これをオートフィルかけた際のように同一名称をまとめて表示できない ものでしょうか? また名前の定義ですが、元データとなる商品リストは随時新商品が追加 となっていく事、元データはcsvデータであることから「名前の定義」は 難しい状況です。 良い知恵をどうかお貸しください。