こんにちは、Ryoです。
Excelで顧客や品番管理を行っていると、多種多様で取り扱いに困ることもありますよね。
私も会社で取り扱う客先情報や品番が相当数あり、都度入力や追加したりする作業がかなり
煩わしいのでVBAのUserForm(ユーザーフォーム)を補助的に使用して手間を省いてます。
客先と品番がまとめられているシートがあれば、その情報を使ってUserFormのリストに表示して任意の品番を選択~セルに書き込んだり、新規客先や品番があればUserFormに入力してデータがまとめられているシートに自動的に追加させたり出来ますので、今回はその活用事例についてご紹介したいと思います。
1.サンプル概要
◆①データを読みFormのリストボックスに一覧表示する
先ず画像のシートは「Extract」という名前にしています。
セル内の【客先】の下の欄は「入力規則」で別シートの客先データをリスト表示しますが、
そのリストから客先を選択した際にUserFormが表示され、Form内のリストボックスに別
シートに入力された品番データを一覧で表示します。
表示された品番を選択し「OK」を押すと【品番】の下のセルに書き込まれるものです。
◆②新規客先や品番を追加する
シート内に配置した「客先・品番登録」ボタンを押すとUserFormが表示され、リストボックスには開く際に読み込んだ登録済み客先一覧があります。
既存の客先に品番を追加する際は「反映⇒」で既存の客先を選択し追加したい品番を本サンプルでは3つまで書き込めます。
新規に客先を登録したい場合は、直接【客先】欄と品番を書き込むことで、データがある
シートに追加するものです。
今回はこの①、②のサンプルについて解説していきます。
2.準備事項
本サンプルの動作概要は上述の通りですが、実行する為の前提条件として、
「DATA」という名前のシートに上の様な形で客先・品番データがあることとしています。
又、本シートの客先データを使って「データ入力規則」を使用します。
元の値に入力されている数式は以下になります。
=OFFSET(DATA!$B$9,0,0,COUNTA(DATA!$B$9:$B$23),1)
OFFSETとCOUNTAを使用するのは、DATAシートの指定範囲から空白を除いてリスト表示する為のものです。
詳細な説明は割愛しますが、OFFSET(基準, 行数, 列数, 高さ, 幅)で、基準とした
セルから指定行数と列数だけシフトした位置の高さと幅の「セル範囲」を返す関数なので、
COUNTAを使って指定範囲の空白ではないセルの個数をカウントし、OFFSET関数の高さを
指定することで空白を除外しています。
。。。ここまで書いておいて何ですが、別に空白除去しなくてもサンプルコード動きますから面倒な時は普通に入力規則の種類をリストにして元の値を=DATA!$B$9:$B$23としても
大丈夫です。
後はサンプル②で使用する「客先・品番登録」ボタンを作って配置しておけばOKです。
3.サンプル①解説
シート内に設定した入力規則のリストで客先を選択した際にUserFormを表示させる為に、
エディタ画面のプロジェクトウィンドウで「Extract」と名前を付けたシートをダブルクリックして以下のコードを記述します。
Private Sub Worksheet_Change(ByVal Target As Range) Dim Exlow As Long Dim ExCol As Integer ExRow = Target.Row ExCol = Target.Column If ExRow = 4 And ExCol = 2 And Cells(4, 2) <> "" Then UserForm1.Caption = "品番抽出" UserForm1.Show vbModeless End If End Sub
このコードで実行しているのは、ターゲットとするセルに変化があった場合に
UserForm1を表示させるというものです。
本サンプルではセルB4(Cells(4,2))になりますから、ターゲットとした
ExRow = Target.Row
ExCol = Target.Column
この部分でExRowが4、ExColが2となり、且つ空白でなければ処理が自動的に実行され、
UserForm1が表示されます。
そのUserForm1は以下の様な形になります。
UserForm1のサンプルコードは以下の通りになります。
Private Sub UserForm_Initialize() 'UserFormの表示位置やサイズ調整用 Me.StartUpPosition = 0 Me.Left = 400 Me.Top = 180 Me.Height = 200 Me.Width = 330 Call CommandButton1_Click End Sub ’---------------------- Private Sub CommandButton1_Click() Dim i As Long Dim tgt As Variant Dim Sh_Name, Cust As String Sh_Name = ActiveSheet.Name ListBox1.Clear For Each tgt In Range("B:B") If tgt = "【客先】" Then tgt.Select Cust = ActiveCell.Offset(1, 0) Exit For End If Next Application.ScreenUpdating = False Worksheets("DATA").Select 'シート内からメイン画面の客先情報と一致するセル検索 For Each tgt In ActiveSheet.UsedRange If tgt = Cust Then tgt.Select '見つけたら品番データをUserFormのリストボックスへ For i = 1 To 5 If ActiveCell.Offset(0, i) <> "" Then ListBox1.AddItem ActiveCell.Offset(0, i) Else Exit For 'データ無しでループ抜け End If Next i Exit For '見つけたら用済みの為ループ抜け End If Next Worksheets(Sh_Name).Activate Application.ScreenUpdating = True End Sub ’------------------------ Private Sub CommandButton2_Click() If ListBox1.ListIndex = -1 Then MsgBox "品番を未選択です", vbCritical Else For Each tgt In Range("B:B") If tgt = "【品番】" Then tgt.Select ActiveCell.Offset(1, 0) = ListBox1.Text Exit For End If Next End If End Sub ’------------------------- Private Sub CommandButton3_Click() Unload UserForm1 End Sub
UserForm_Initialize()では表示した際のサイズや表示位置を調整する為の記述をしています。
ここの数値はお好みで変えても大丈夫です。
表示すると同時にCallでCommandButton1_Click()を実行させます。
CommandButton1_Click()は客先情報を読み込み、DATAシートを検索して一致した位置から品番データを読み込み、 ListBox1.AddItemを使ってリスト化します。
CommandButton2_Click()は一覧表示された品番データを選択して、対象ボタンを押すことでサンプルのセルB9に品番データを書き込む処理をします。
CommandButton3_Click()はFormを閉じる処理になります。
特に難しい処理は無く、覚えておくと便利なのは指定したセルが書き換わると自動的に処理が実行されるWorksheet_Change(ByVal Target As Range)や、Formのリストに関する
ListBox1.AddItem・・・ですね。
後は本サンプルで無理に使う必要がないFor Eachですが、何かと有用なので使い方の参考になればと思い敢えて使ったりしてます(笑)
For Eachは以前のこちらの記事でも紹介していますので、ご参考までに。
4.サンプル②解説
こちらで使用するUserFormは以下になります。
サンプルコードはこの通りです。
Private Sub UserForm_Activate() 'Form表示する際に既に登録されている客先データを読み込む Dim i As Long Dim tgt As Variant Dim Sh_Name, Cust As String Sh_Name = ActiveSheet.Name ListBox1.Clear Application.ScreenUpdating = False Worksheets("DATA").Select For Each tgt In ActiveSheet.UsedRange If tgt = "客先" Then tgt.Select For i = 1 To 15 If ActiveCell.Offset(i, 0) <> "" Then 'ここでリスト化する ListBox1.AddItem ActiveCell.Offset(i, 0) Else Exit For End If Next i Exit For End If Next Worksheets(Sh_Name).Activate Application.ScreenUpdating = True End Sub '------------------------------- Private Sub CommandButton1_Click() Dim tgt As Variant Dim cnt, i, NumA, NumB, addflg As Integer Dim Target, Sh_Name、Cell_Ad As String Dim Model(1 To 3) As Variant Dim MyRow, MyCol As Long Sh_Name = ActiveSheet.Name Application.ScreenUpdating = False Worksheets("DATA").Select For i = 1 To 3 'Form品番データが空欄じゃなければ読み込む If UserForm2.Controls("TextBox" & i + 1).Value <> "" Then Model(i) = UserForm2("TextBox" & i + 1).Value cnt = cnt + 1 End If Next i Target = Me.TextBox1 '客先=Target For Each tgt In Range("B8:B23") Select Case tgt '客先を探すのは新規登録の際に空きの場所を特定する為 Case Is = "客先" tgt.Select MyCol = ActiveCell.Column NumA = WorksheetFunction.CountA(Range(Cells(9, MyCol), _ Cells(23, MyCol))) If NumA = 15 Then MsgBox "客先欄に空きがありません", vbCritical Exit Sub Else Cell_Ad = ActiveCell.Offset(NumA + 1, 0).Address _ (RowAbsolute:=False, ColumnAbsolute:=False) End If Case Is = Target tgt.Select MyRow = ActiveCell.Row addflg = 1 For i = 1 To cnt NumB = WorksheetFunction.CountA(Range(Cells(MyRow, 3), _ Cells(MyRow, 7))) If NumB = 5 Then MsgBox "入力可能なセルがありません", vbCritical Exit Sub Else ActiveCell.Offset(0, NumB + 1) = Model(i) End If Next i End Select Next If addflg <> 1 Then Range(Cell_Ad).Select ActiveCell = Target For i = 1 To cnt ActiveCell.Offset(0, i) = Model(i) Next i End If Worksheets(Sh_Name).Activate Application.ScreenUpdating = True MsgBox "登録完了", vbInformation Unload UserForm2 End Sub '------------------------------- Private Sub CommandButton2_Click() Unload UserForm2 End Sub '------------------------------- Private Sub CommandButton3_Click() If ListBox1.ListIndex = -1 Then MsgBox "客先を未選択です", vbCritical Else TextBox1 = "" TextBox1 = ListBox1.Text End If End Sub
先ずUserForm2を表示する際に登録済みの客先データを読み込むので、その処理内容が
UserForm_Activate()に記述した内容ですが、サンプル①の処理とほぼ同様ですね。
CommandButton1_Click()の処理ですが、ここで覚えておくと後々助かる部分としてFormに配置したテキストボックスの空判定です。
If UserForm2.Controls(“TextBox” & i + 1).Value <> “” Then
この様に記述していますが、UserForm2.Controls(“TextBox”・・・と書くことで成立して、他の記述の仕方(例えばIf TextBox1 <>”” Then・・・やIsEmptyなど)では上手く判定できませんでしたので、こうしています。
後はFor Eachで検索して、新規に客先を追加する場合のセルアドレス取得と客先の登録有無をチェックして有ればテキストボックスに記載された品番を書き込む処理を行っています。
範囲指定はシート全体だったりセル範囲だったりしてますが、ここは意図的に指定方法を変えているので、やり方の参考になればと思った次第です。
CommandButton2_Click()はキャンセル対応、CommandButton3_Click() は客先指定されていない場合の警告表示処理となっています。
◆使用例
本サンプルで例えばM社を追加して品番M001,M002を追加する場合は、
「客先・品番登録」ボタンを押してFormを表示し、画像の通り入力して「実行」を押すと、
登録完了のダイアログが表示され、DATAシートを見るとこの通り登録されますので、ここでサンプル①で設定した入力規則で見ると存在しています。
そのM社を選択すれば、サンプル①のFormが表示され、品番が選択できます。
このような形になりますので、普段まとめて管理しているデータシートなどを上手く活用することが出来るのではないかと思います。
以上がUserFormのリスト活用事例になります。
書き始める前はもっとあっさり書くつもりでしたが、気が付けば長くなりました。。。
会社で扱う製品や仕組みによって様々ですからうまくマッチして使えるものではないと思いますが、何かの参考になれれば幸いです。
Ryo