ねらい:どのツールにも流用できる「フォームUIの型」を持つ
フォームUIテンプレのゴールは、こうです。
「毎回ゼロからUserFormを作る」のではなく、「決まった型」に沿って作れば、どの業務ツールにも同じ操作感・同じコード構造でフォームを付けられるようにすることです。
ここでは、実務でよくある「設定を選んで実行するタイプ」のフォームを例に、
初心者でも真似しやすい“標準UserForm構造”をテンプレとしてまとめます。
フォームUIテンプレの全体構造
3つの役割に分けて考える
フォームUIは、次の3つに分けると整理しやすくなります。
画面(UserForm本体とコントロール)
入力値の受け渡し(プロパティや専用の「結果クラス」)
実際の処理(既存のバッチやノーコードエンジンを呼ぶ部分)
重要なのは、「フォームの中に業務ロジックを書き込まない」ことです。
フォームはあくまで「ユーザーから条件をもらう窓口」であり、処理は標準モジュール側に任せる——これを徹底すると、後からの修正がとても楽になります。
今回作るテンプレのイメージ
今回のテンプレでは、こんなフォームを想定します。
対象日付を選ぶテキストボックス(またはコンボボックス)
処理モードを選ぶコンボボックス(例:日次/月次)
実行ボタン
キャンセルボタン
このフォームで条件を選び、「実行」を押すと RunDailyJobs のようなメイン処理を呼び出す、という形にします。
UserFormデザインの基本テンプレ
コントロールの配置と名前付け
VBEで「挿入 → ユーザーフォーム」を選び、UserForm1 を追加します。
プロパティウィンドウで、フォームの Name を frmMain、Caption を「日次処理メニュー」などに変更します。
フォーム上に、次のコントロールを配置します。
ラベル(Caption: 対象日)+テキストボックス(Name: txtDate)
ラベル(Caption: 処理モード)+コンボボックス(Name: cboMode)
コマンドボタン(Name: cmdRun, Caption: 実行)
コマンドボタン(Name: cmdCancel, Caption: キャンセル)
ここで一番大事なのは「Nameをきちんと付ける」ことです。
txtDate、cboMode、cmdRun、cmdCancel のように、役割が一目で分かる名前にしておくと、コードを書くときに迷いません。
フォームの基本コードテンプレ
初期化イベントでコンボボックスなどをセットする
UserFormのコードウィンドウに、初期化処理を書きます。
' frmMain コード
Option Explicit
Private Sub UserForm_Initialize()
Me.cboMode.Clear
Me.cboMode.AddItem "日次"
Me.cboMode.AddItem "月次"
Me.txtDate.Value = Format(Date, "yyyy/mm/dd")
End Sub
VBUserForm_Initialize は、フォームが表示される直前に一度だけ呼ばれるイベントです。
ここで「コンボボックスの選択肢を設定する」「初期値を入れる」といった“画面の初期状態”を整えます。
実行ボタンクリックのテンプレ
実行ボタンには、「入力チェック → フォームを閉じる → 外側の処理を呼ぶためのフラグ設定」という流れを書きます。
まず、フォームのモジュールに「OKが押されたかどうか」を表すフラグを持たせます。
Private m_IsOk As Boolean
Public Property Get IsOk() As Boolean
IsOk = m_IsOk
End Property
VB次に、実行ボタンのクリックイベントを書きます。
Private Sub cmdRun_Click()
If Not ValidateInput() Then
Exit Sub
End If
m_IsOk = True
Me.Hide
End Sub
VBここで重要なのは、「Unload ではなく Hide を使う」ことです。
Hide にすると、フォームを閉じた後でも、外側から frmMain.txtDate.Value のように入力値を参照できます。
入力チェックは、別プロシージャに切り出しておきます。
Private Function ValidateInput() As Boolean
If Trim(Me.txtDate.Value) = "" Then
MsgBox "対象日を入力してください。", vbExclamation
Me.txtDate.SetFocus
ValidateInput = False
Exit Function
End If
If IsDate(Me.txtDate.Value) = False Then
MsgBox "対象日が日付として正しくありません。", vbExclamation
Me.txtDate.SetFocus
ValidateInput = False
Exit Function
End If
If Me.cboMode.ListIndex < 0 Then
MsgBox "処理モードを選択してください。", vbExclamation
Me.cboMode.SetFocus
ValidateInput = False
Exit Function
End If
ValidateInput = True
End Function
VBこのように「チェック専用の関数」を用意しておくと、コードが読みやすくなり、再利用もしやすくなります。
キャンセルボタンクリックのテンプレ
キャンセルはシンプルです。
Private Sub cmdCancel_Click()
m_IsOk = False
Me.Hide
End Sub
VBキャンセル時は IsOk を False のままにしておき、外側で「処理を実行しない」という判断に使います。
フォームと処理をつなぐ標準モジュール側のテンプレ
フォームを表示して結果を受け取るSub
標準モジュール(例えば ModEntry)に、「フォームを出してから処理を呼ぶ」Subを書きます。
' ModEntry.bas
Option Explicit
Public Sub ShowMainFormAndRun()
Const MODULE_NAME As String = "ShowMainFormAndRun"
On Error GoTo ErrHandler
Dim f As frmMain
Set f = New frmMain
f.Show
If f.IsOk Then
Dim targetDate As Date
targetDate = CDate(f.txtDate.Value)
Dim modeName As String
modeName = CStr(f.cboMode.Value)
RunDailyJobsWithParam targetDate, modeName
End If
Unload f
Exit Sub
ErrHandler:
LogError MODULE_NAME, "MAIN", Err
MsgBox "フォーム処理中にエラーが発生しました。", vbExclamation
End Sub
VBここでの重要ポイントは、次の3つです。
フォームは New でインスタンスを作り、Show で表示する。
閉じた後、IsOk を見て「実行するかどうか」を判断する。
必要な値だけを取り出して、RunDailyJobsWithParam のような“処理専用Sub”に渡す。
こうすることで、「フォームの中に業務ロジックを書かない」というルールを守れます。
パラメータ付きのメイン処理テンプレ
フォームから受け取った値を使う処理は、別Subとして定義します。
Public Sub RunDailyJobsWithParam(ByVal targetDate As Date, ByVal modeName As String)
Const MODULE_NAME As String = "RunDailyJobsWithParam"
On Error GoTo ErrHandler
LogStart MODULE_NAME, "日次処理開始: 日付=" & Format(targetDate, "yyyy/mm/dd") & ", モード=" & modeName
' ここで、受け取ったパラメータを使って処理を分岐させる
If modeName = "日次" Then
RunBatch ' 例えば日次用ConfigBatchを読む
ElseIf modeName = "月次" Then
' 月次用の別バッチを呼ぶなど
End If
LogEnd MODULE_NAME, "日次処理終了"
Exit Sub
ErrHandler:
LogError MODULE_NAME, "MAIN", Err
MsgBox "日次処理中にエラーが発生しました。", vbExclamation
End Sub
VBここまで来ると、「フォームは条件を集める」「標準モジュールは処理を実行する」という役割分担がはっきりします。
例題:簡単な「検索フォームUI」をテンプレから作る
やりたいことのイメージ
シート上の顧客一覧から、「顧客コードを入力して、その行にジャンプする」フォームを作るとします。
このときも、同じテンプレ構造で考えます。
UserForm側には、顧客コード入力用の TextBox(txtCustomerCode)と、検索ボタン(cmdSearch)、閉じるボタン(cmdClose)を置きます。
標準モジュール側に、「顧客コードを受け取って該当行に選択を移動する」Subを書きます。
フォーム側のコード
' frmSearchCustomer
Option Explicit
Private Sub cmdSearch_Click()
If Trim(Me.txtCustomerCode.Value) = "" Then
MsgBox "顧客コードを入力してください。", vbExclamation
Me.txtCustomerCode.SetFocus
Exit Sub
End If
SearchCustomerByCode Me.txtCustomerCode.Value
End Sub
Private Sub cmdClose_Click()
Unload Me
End Sub
VBここでは、「検索ボタンを押したら、標準モジュールの SearchCustomerByCode を呼ぶ」というだけにしています。
標準モジュール側のコード
' ModCustomerSearch
Option Explicit
Public Sub ShowCustomerSearchForm()
frmSearchCustomer.Show
End Sub
Public Sub SearchCustomerByCode(ByVal custCode As String)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Customer")
Dim rng As Range
Set rng = ws.Range("A:A").Find(What:=custCode, LookAt:=xlWhole)
If rng Is Nothing Then
MsgBox "顧客コード [" & custCode & "] は見つかりませんでした。", vbInformation
Else
ws.Activate
rng.Select
End If
End Sub
VBこの例題でも、「フォームはUIだけ」「検索ロジックは標準モジュール」という分離を守っています。
この“分け方”が、フォームUIテンプレの一番大事な部分です。
重要ポイントの深掘り:フォームUIテンプレを“使い回せる型”にするコツ
フォームの役割を「入力と表示」に限定する
フォームの中に、バッチ処理やJOINロジックを書き始めると、
そのフォームは「その業務専用の巨大な塊」になってしまいます。
テンプレとして長く使えるフォームは、役割がシンプルです。
入力値を集める
選択肢を表示する
ボタン操作を受け取る
それ以上のことは、標準モジュールに任せる——この線引きを意識してみてください。
「フォーム→処理」の接続をいつも同じパターンにする
毎回違う書き方をすると、後から読むときに混乱します。
次のパターンを“お約束”にしてしまうと、かなり楽になります。
標準モジュールに「フォームを表示するSub」を置く
その中で Dim f As frmX : Set f = New frmX : f.Show とする
必要なら IsOk やプロパティで値を受け取り、処理用Subに渡す
最後に Unload f で片付ける
この型を守ると、「フォームの出し方」がどのツールでも同じになり、
新しいフォームを作るときも迷いません。
入力チェックは必ず専用プロシージャに切り出す
ValidateInput のような関数にまとめておくと、
チェック項目を増やしたり、メッセージを変えたりするときに、
その関数だけ見れば済みます。
ボタンクリックイベントの中身は、できるだけ短くする。
「チェック → フラグ設定 → Hide」くらいに留める。
この“短さ”が、読みやすさと保守性を大きく左右します。
まとめ:フォームUIテンプレは「画面と処理を分けるための型」
今回のフォームUIテンプレを一言で言うと、こうです。
UserFormは「入力と表示」だけを担当し、
標準モジュールが「処理」を担当する。
両者の間は、「Showして値を受け取る」「ボタンクリックで処理用Subを呼ぶ」という決まったパターンでつなぐ。
この型さえ一度身につけてしまえば、
「このツールにも簡単なメニュー画面を付けたいな」と思ったときに、
迷わず同じ構造でフォームを生やしていけます。
