画面に表示するメッセージの管理についてですが、Javaや.NETなどでアプリケーションを作成する場合には、定義を外出しにすることがほとんどだと思います。
しかし、ExcelVBAのアプリケーションの場合は、メッセージ管理されているものが少なく、ほとんどがソースコードの中にハードコーディングされている気がします。
CONSTで定義されているものはマシで、Msgbox関数にメッセージが直書きされているものも多いです。
Excelはシートにデータを持つことができるので、メッセージはシートで管理すべきと考えています。
具体的な方法について記載していきたいと思います。
メッセージをソースで管理するデメリット
メッセージをソースで管理するデメリットは、以下2つがあるかと思います。
- ソースを変更するので、(現場のルールによっては)テストが必要になる
- 同じようなメッセージを作成してしまう危険がある
ソースに直書きしてしまうと、メッセージの内容を変更したいときに、ソースを検索して修正をしなくてはいけなくなります。
メッセージの文言とはいえ、ソースを修正するとテストが必要になるケースが多いです。
また、メッセージが一覧で管理されていないと似たメッセージを複数作成してしまう危険があります。
例えば、既に「商品が取得できません。」というメッセージを定義している定数があるのに「商品がありません。」というメッセージの定数を作ってしまうなどです。
その場合、「商品という言葉は製品に変えてくれ」と顧客に言われた場合に修正量がかなり多くなってしまいます。
メッセージが一覧で見れるようになっていれば、上記のような重複を防ぐことが出来ます。
シートにメッセージの一覧を作成する
冒頭に記載した通り、メッセージの一覧を保持しているシートを作成し、そこにメッセージ定義を書いて管理するのが良いかと思います。
具体的には以下の列を作成して管理します。
項目 | 説明 |
---|---|
メッセージ管理番号 | メッセージを一意に特定する番号を設定する。この番号を使用してメッセージを呼び出す |
タイトル | ウィンドウタイトルを設定する。 |
内容 | メッセージの本文を設定する。 |
アイコンの種類 | アイコンの種類を設定する。 |
ボタンの種類 | ボタンの種類を設定する。 |

アイコンの種類はリストボックスで以下を設定できるようにします。
- vbCritical
- vbQuestion
- vbExclamation
- vbInformation
ボタンの種類はリストボックスで以下を設定できるようにします。
- vbOKOnly
- vbOKCancel
- vbAbortRetryIgnore
- vbYesNoCancel
- vbYesNo
- vbRetryCancel
ボタンの種類とアイコンは、メッセージ上の以下の箇所のことです。

そして、上記シートに記載した「メッセージ管理番号」を引数で与えればメッセージが表示されるようにVBAでプログラムを作成します。
メッセージの一覧からメッセージを呼び出すVBAプログラム
以下のようなプログラムを作成し、メッセージを呼び出す共通関数として使用します。
↓クラスモジュールで作成(MsgDataクラス)
Option Explicit
Enum COLS
COL_NO = 1
COL_TITLE
COL_CONTEXT
COL_ICON
COL_BUTTONS
End Enum
Private title As String
Private context As String
Private buttons As Integer
Public Sub setcontextData(ws As Worksheet, row As Long)
title = ws.Cells(row, COLS.COL_TITLE).Value
context = ws.Cells(row, COLS.COL_CONTEXT).Value
Select Case ws.Cells(row, COLS.COL_BUTTONS).Value
Case "vbOKOnly"
buttons = vbOKOnly
Case "vbOKCancel"
buttons = vbOKCancel
Case "vbAbortRetryIgnore"
buttons = vbAbortRetryIgnore
Case "vbYesNoCancel"
buttons = vbYesNoCancel
Case "vbYesNo"
buttons = vbYesNo
Case "vbRetryCancel"
buttons = vbRetryCancel
End Select
Select Case ws.Cells(row, COLS.COL_ICON).Value
Case "vbCritical"
buttons = buttons + vbCritical
Case "vbQuestion"
buttons = buttons + vbQuestion
Case "vbExclamation"
buttons = buttons + vbExclamation
Case "vbInformation"
buttons = buttons + vbInformation
End Select
End Sub
Public Sub showMsg()
Call MsgBox(context, buttons, title)
End Sub
↓標準モジュールで作成
Private dicMsg As Object
Private Sub init()
Const SHEET_NAME = "メッセージ定義"
Const COL_NO = 1
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets(SHEET_NAME)
Dim row As Long
Dim clsMsg As msgData
Set dicMsg = CreateObject("Scripting.Dictionary")
For row = 2 To ws.Cells(Rows.Count, 1).End(xlUp).row
If Not dicMsg.exists(ws.Cells(row, COL_NO).Value) Then
Set clsMsg = New msgData
Call clsMsg.setcontextData(ws, row)
dicMsg.Add ws.Cells(row, COL_NO).Value, clsMsg
End If
Next
End Sub
Public Sub openMsg(id As String)
If dicMsg Is Nothing Then init
If dicMsg.exists(id) Then
Dim clsMsg As msgData
Set clsMsg = dicMsg.Item(id)
Call clsMsg.showMsg
Else
MsgBox "未定義のエラーです"
End If
End Sub
↓呼び出し方法
Public Sub test()
Call openMsg("MSG001")
End Sub
↓結果

メッセージ一覧を定義しているワークシート名は「メッセージ定義」というワークシート名になっていることを想定しています。
以下からサンプルをダウンロードできます。
https://vbaexcel.slavesystems.com/product/Msgサンプル.zip
メッセージに引数を指定できるようにする
上記の方法を使用していると不便に感じることが出てくるかもしれません。
それは、一部だけが異なるメッセージを使いまわしたい場合です。
具体例を出すと、以下のメッセージを定義しなければいけないとします。
- 同じ取引先は登録することができません
- 同じ部署は登録することができません
- 同じ社員は登録することができません
上記は「取引先、部署、社員」という文言が違うだけで他はすべて同じです。
仮に、「登録できません。」の部分を変更する必要が発生した場合は修正するメッセージが多くなってしまいます。
そこで、「取引先、部署、社員」の部分を引数で渡すよう実装するのが良いかと思います。
まず、ワークシート上のメッセージ定義を以下のようにします。
同じ#{1}は登録することができません
そして、上記の#{1}の部分をreplaceするようにVBAのコードを書けばよいかと思います。
Public Sub openMsg(id As String, ParamArray arg() As Variant)
If dicMsg Is Nothing Then init
If dicMsg.exists(id) Then
Dim clsMsg As msgData
Set clsMsg = dicMsg.Item(id)
For i = 0 To UBound(arg)
clsMsg.context = Replace(clsMsg.context, "#{" & i + 1 & "}", "")
Next
Call clsMsg.showMsg
Else
MsgBox "未定義のエラーです"
End If
End Sub
コメントを残す