- 確認・通知のダイアログを表示したい
- ユーザーから1つの値を受け取りたい
- 複数の入力項目をまとめて受け取りたい
この記事を読めば、目的に応じてMsgBox・InputBox・UserFormを適切に使い分けられるようになります。
VBAでユーザーとやり取りする手段は、大きく分けてこの3つです。それぞれ役割が異なるので、まずは全体像から整理します。
- 3つの手段の使い分け基準
- MsgBoxの引数・戻り値
- InputBoxの2種類と違い
- UserFormの作成とイベント処理
- 入力値の検証と呼び出し元への受け渡し
MsgBox・InputBox・UserFormは何が違うのか
3つの手段は、「受け取れる情報の量」で役割が分かれています。
| 用途 | 適した手段 | 理由 |
|---|---|---|
| 確認・通知のみ(入力不要) | MsgBox | ボタンとアイコンを表示する専用の関数で、文字列や数値の入力は受け付けない |
| 1つの値を受け取りたい | InputBox / Application.InputBox | 単一の入力欄のみを持つ、シンプルな入力用の関数 |
| 複数項目・独自レイアウトが必要 | UserForm | TextBox・ListBox・ComboBoxなど複数のコントロールを自由に配置できる |
MsgBoxとInputBoxはどちらも1行のコードで呼び出せる組み込み関数です。一方UserFormは、フォームをあらかじめ設計しておく必要がある分、表現の自由度が高くなります。
MsgBoxで確認・通知を表示する
基本構文と最小コード
最も単純な形は、メッセージを1つ渡すだけです。
MsgBox "処理が完了しました。"MsgBox関数の正式な構文は次のとおりです。
MsgBox(prompt, buttons, title)promptはメッセージ本文、buttonsはボタン・アイコンの種類、titleはタイトルバーの文字列です。buttonsとtitleは省略できます。
ボタンの種類とアイコンを指定する
buttons引数には、ボタンの構成とアイコンの種類を、定数を+(プラス)で組み合わせて指定します。
| 分類 | 定数 | 内容 |
|---|---|---|
| ボタン構成 | vbOKOnly | OKのみ(既定値) |
| vbOKCancel | OK・キャンセル | |
| vbAbortRetryIgnore | 中止・再試行・無視 | |
| vbYesNoCancel | はい・いいえ・キャンセル | |
| vbYesNo | はい・いいえ | |
| vbRetryCancel | 再試行・キャンセル | |
| アイコン | vbCritical | エラーアイコン(赤い×) |
| vbQuestion | 確認アイコン(?) | |
| vbExclamation | 警告アイコン(!) | |
| vbInformation | 情報アイコン(i) |
ボタン構成とアイコンを組み合わせる例です。
MsgBox "この内容で確定しますか?", vbYesNo + vbQuestion, "確認"戻り値で処理を分岐する
MsgBoxは、押されたボタンに応じた戻り値を返します。戻り値を変数で受け取れば、その後の処理を分岐できます。
Dim result As VbMsgBoxResult
result = MsgBox("この内容で確定しますか?", vbYesNo + vbQuestion, "確認")
If result = vbYes Then
MsgBox "処理を実行します。"
Else
MsgBox "処理をキャンセルしました。"
End If戻り値の判定に使う定数は、vbOK・vbCancel・vbAbort・vbRetry・vbIgnore・vbYes・vbNoの7種類です。押されたボタンに対応する定数と比較します。
メッセージを改行する
改行を入れたい場合は、改行を表す定数vbCrLfを文字列と連結します。
MsgBox "入力内容を確認してください。" & vbCrLf & "問題なければOKを押してください。"InputBoxで1つの値を受け取る
VBAで値を1つ受け取る手段には、組み込みのInputBox関数とApplication.InputBoxメソッドの2種類があります。名前は似ていますが、戻り値の型と使いどころが異なります。
VBA組み込みのInputBox関数
組み込みのInputBox関数は、常に文字列(String型)を返します。
Dim inputValue As String
inputValue = InputBox("名前を入力してください。", "入力", "山田太郎")
If inputValue = "" Then
MsgBox "入力がキャンセルされました。"
Else
MsgBox inputValue & "さん、こんにちは。"
End If第1引数がメッセージ、第2引数がタイトル、第3引数が入力欄の初期値です。3つとも文字列で指定します。
Application.InputBoxで型を指定する
Application.InputBoxメソッドは、Type引数で戻り値の型を指定できる点が組み込み関数との違いです。特にType:=8を指定すると、セル範囲(Range型)を選択させることができます。
Dim targetRange As Range
On Error Resume Next
Set targetRange = Application.InputBox("集計するセル範囲を選択してください。", "範囲選択", Type:=8)
On Error GoTo 0
If targetRange Is Nothing Then
MsgBox "範囲が選択されませんでした。"
Else
MsgBox "選択範囲: " & targetRange.Address
End IfType引数に指定できる主な値は次のとおりです。複数の型を許可したい場合は、値を合計して指定します(例: 数値と文字列を許可する場合は1+2=3)。
| 値 | 戻り値の型 |
|---|---|
| 0 | 数式(文字列として) |
| 1 | 数値 |
| 2 | 文字列 |
| 4 | 論理値(True / False) |
| 8 | セル参照(Range) |
| 16 | エラー値(#N/A など) |
| 64 | 数値の配列 |
キャンセル時の挙動の違いに注意する
2つの手段は、キャンセル時の戻り値がまったく異なります。これは実装時に混同しやすいポイントです。
- 組み込みInputBox:キャンセルすると空文字列(””)を返す。「何も入力せずOK」を押した場合も同じく空文字列になるため、この2つを区別できない
- Application.InputBox:キャンセルするとブール値のFalseを返す。Range型の変数にFalseを代入しようとすると型不一致の実行時エラーになるため、上記コード例のようにOn Error Resume Nextでエラーを無視してから、Is Nothingで判定する必要がある
UserFormで複数項目の入力フォームを作る
複数の項目をまとめて受け取りたい場合や、選択肢から選ばせたい場合は、UserFormを使います。
フォームを追加してコントロールを配置する
UserFormの作成手順は次のとおりです。
- VBEを開く(Alt+F11)
- 「挿入」メニューから「ユーザーフォーム」を選択する
- ツールボックスからTextBox・ListBox・CommandButtonなどをフォーム上にドラッグ&ドロップする
- プロパティウィンドウで各コントロールの(Name)を設定する
(Name)プロパティは、コードから参照するときの識別子になります。既定のTextBox1のままでも動作しますが、txtName・lstCity・btnOKのように役割がわかる名前に変更しておくと、後述するイベントプロシージャの見通しがよくなります。
イベントプロシージャの基本形
UserFormの動作は、コントロール名_イベント名という名前のプロシージャに記述します。VBEのコード画面上部にある2つのドロップダウンから、対象のコントロールとイベントを選択すると、プロシージャの雛形が自動生成されます。
ボタンがクリックされたときの処理はClickイベント、フォームが表示される直前の初期化処理はUserForm_Initializeイベントに書きます。
Private Sub UserForm_Initialize()
Me.lstCity.AddItem "東京"
Me.lstCity.AddItem "大阪"
Me.lstCity.AddItem "福岡"
Me.lstCity.ListIndex = 0
End Sub
Private Sub btnOK_Click()
Me.Hide
End SubListIndexプロパティに0を指定すると、ListBoxの1番目の項目(東京)が初期状態で選択された状態になります。
Showメソッドでモーダル・モードレスを切り替える
フォームを表示するにはShowメソッドを使います。引数によって、フォームを表示している間に他の操作を受け付けるかどうかが変わります。
UserForm1.Show ' モーダル(既定): フォームを閉じるまで他の操作を受け付けない
UserForm1.Show vbModeless ' モードレス: 表示したまま他の操作もできる入力を完了させてから後続の処理に進みたい場合はモーダル、フォームを表示したままシート側の操作もさせたい場合はモードレスを選びます。引数を省略した場合はモーダルになります。
入力値を呼び出し元に渡す
Me.Hideでフォームを非表示にした直後は、フォームのインスタンス自体はまだメモリ上に残っています。そのため、呼び出し元のコードからフォーム上のコントロールの値に直接アクセスできます。
Dim frm As UserForm1
Set frm = New UserForm1
frm.Show
MsgBox frm.txtName.Value & "さんが入力されました。"
Unload frmフォームモジュールにPublicなプロパティやフラグ変数を用意しておくと、キャンセル状態のようにコントロールの値だけでは表せない情報も呼び出し元に伝えられます。
' フォームモジュール(UserForm1)側
Public Cancelled As Boolean
Private Sub btnCancel_Click()
Cancelled = True
Me.Hide
End Subフォーム内部の変数を直接公開せず、Property Get / Property Letプロシージャ経由でアクセスさせる書き方もあります。外部から値を書き換えられたくない場合や、取得時に加工処理を挟みたい場合に使います。
' フォームモジュール(UserForm1)側
Private m_UserName As String
Public Property Get UserName() As String
UserName = m_UserName
End Property
Private Sub btnOK_Click()
m_UserName = Me.txtName.Value
Me.Hide
End Subフォーム内で入力値を検証する
OKボタンが押された時点で、必須項目が空でないかをチェックし、問題があればフォームを閉じずにメッセージだけ表示するのが基本パターンです。
Private Sub btnOK_Click()
If Me.txtName.Value = "" Then
MsgBox "名前を入力してください。", vbExclamation, "入力エラー"
Exit Sub
End If
Me.Hide
End SubExit Subでプロシージャを抜けることで、Me.Hideが実行されずフォームは表示されたままになります。ユーザーは同じフォーム上で入力をやり直せます。
通しサンプル:名前と都市を入力するフォーム
ここまでの内容をまとめて、TextBox(名前)とListBox(都市)を持つフォームの例を示します。
フォームには、txtName(TextBox)・lstCity(ListBox)・btnOK(CommandButton)・btnCancel(CommandButton)の4つのコントロールを配置している前提です。
' UserForm1 側のコード
Public Cancelled As Boolean
Private Sub UserForm_Initialize()
Me.lstCity.AddItem "東京"
Me.lstCity.AddItem "大阪"
Me.lstCity.AddItem "福岡"
Me.lstCity.ListIndex = 0
Cancelled = False
End Sub
Private Sub btnOK_Click()
If Me.txtName.Value = "" Then
MsgBox "名前を入力してください。", vbExclamation, "入力エラー"
Exit Sub
End If
Me.Hide
End Sub
Private Sub btnCancel_Click()
Cancelled = True
Me.Hide
End Sub' 標準モジュール側のコード
Sub ShowNameForm()
Dim frm As UserForm1
Set frm = New UserForm1
frm.Show
If frm.Cancelled Then
MsgBox "入力がキャンセルされました。"
Else
MsgBox frm.txtName.Value & "さん(" & frm.lstCity.Value & ")で登録します。"
End If
Unload frm
End Sub標準モジュール側でUnload frmを呼び出し、フォームのインスタンスを確実に破棄しています。frm.Showの直後にフォームの値を読み取ってから、Unloadする順序を守ります。
発展Tips:ListBoxへの複数列追加とフォームの後始末
ListBoxは、ColumnCountプロパティを設定すると、1つの項目に複数列のデータを持たせられます。
With Me.lstItems
.ColumnCount = 2
.AddItem "A001"
.List(.ListCount - 1, 1) = "商品A"
End WithAddItemで1列目(商品コード)を追加したあと、Listプロパティにインデックスと列番号を指定して2列目(商品名)を設定しています。列番号は0始まりです。
複数のフォームを扱うマクロでは、UnloadしないままSetを繰り返すと、使われなくなったフォームのインスタンスがメモリ上に残り続けます。フォームの役目が終わったら、Unloadで確実に破棄することが推奨されます。
まとめ
確認・通知はMsgBox、1つの値の取得はInputBox、複数項目やレイアウトが必要な場合はUserFormと、受け取りたい情報の量に応じて選べば迷いません。
セルやシートの基本操作については、以下の記事もあわせてご覧ください。

コメント