昔は、人を番号で呼ぶのは刑務所だけでしたが、最近は、個人情報保護の観点からお客様を氏名で呼ぶのではなく、番号で呼び出すのが当たり前になっているようです。特に、受付カードを発券して、大型モニタに呼出番号を表示し、音声案内で窓口に呼び出す仕組みのことを「呼出番号表示システム」といいます。官公庁、銀行、医療機関などで使われている本格的なものは導入するのに数十万円~数百万円かかります。
しかし、簡単なものであればExcelで作ることができます。Excelの入ったパソコンとモニタ2台さえあればタダで作れます。そこで、今回は、この呼出表示をExcelで作る方法について解説します。
なお、「Excelで簡単に作れる」とは言っても、人によって「簡単」のレベルが違います。この記事に書いてあることが簡単だと感じなければ、まだまだExcelの修行が足りないと思って当サイトで学習していただければ幸いです(宣伝)。
目次
1.ここで問題です。
当サイトは「問題集」なので、問題として出題します。
問題
次の条件で、番号札を取った客を番号で呼び出す装置を作成しなさい。
- 音声ファイルを除いて、Excelだけを使用する。
- 入力は原則として1つのセルのみとし、テンキーを使用する。
- 自動で音声案内をする。
- 呼び出し以外の連絡事項も表示できる。
- 呼出し番号は、1番~999番とする。
- 窓口は1か所で、最大で9名まで呼出し可能。
補足説明
この問題の状況を説明します。窓口に1つのパソコンを置いて、受付の人がモニタを見ながら操作をします。
窓口のモニタには操作用のExcelファイルが表示され、入力する箇所は1つのセルのみです。
できるだけ簡単に操作できるようにするため、Excelに入力するときは原則としてマウスやキーボードを使わず、標準的なテンキー(0~9の数字、四則演算、Enterキー)のみで操作できるようにします。
さらに、同じパソコンにモニタを1台増設して、お客様向け表示用のExcelファイルをお客様に向けて表示します(参考:パソコン2画面で仕事がはかどる?初心者のためのマルチモニタ講座【デュアルディスプレイ】)。
なお、外部のテキストファイルに自動出力&取り込みのマクロを作ることによって、別のパソコンに表示させることも可能ですが、今回は、問題を簡単にするため同一のパソコンを使用するものとします。
2つのExcelファイルは連動します。
2.完成イメージ
一例として、次のような設計にしてみました。完成イメージは動画でご覧ください。
- 操作用Excelと表示用Excelがある。入力するのは操作側の1か所のみ。
- 番号を入力してEnterキーを押すと、操作画面に左上から順に表示される。
- それと同時に表示用にも表示される。
- 音声案内も流れる。
- 入力したセルは空白になり、自動的に選択状態になる。
- 画面に表示されているものと同じ番号の場合は番号を追加せず、音声案内のみ。
- テンキー(電卓)と同じ並び順で「1-」~「9-」の削除キーが入力されている。数字とマイナスの組み合わせの場合は、該当する番号が削除され、空いた枠を詰める。
- アスタリスク3つで全部削除。
- 表示用のExcelファイルは複数のシートで構成されていて、案内表示を切り替えることができる。数字の後にプラスを入力するとそのシート番号に切り替わる。「1+」で元に戻る。
- 呼出は最大9人まで、1番から999番まで
3.入力規則
問題
セルD4に、テンキーで半角数字または半角記号を入力する。全角を入力できないようにするにはどうすればよいか。
解説
セルD4を選択します。データタブ-入力規則の画面を表示します。
日本語入力を無効またはオフにします。
4.音声ファイルについて
音声案内は次のような文章とします。
「ピンポーーン、543番のカードをお持ちの方は窓口までお越しください。」
ピンポーーンの音声のほかに、100の位、10の位、1の位で、あわせて29個の音声ファイルを使います。拡張子はwavでもmp3でもかまいません。
音声ファイルを1本につなげましたので、使いたい人は使ってください。
5.分割のメリット
「何のためにExcelVBAの練習をするのか」を考えましょう。
呼出番号表示システムのように、すでに運用されている仕組みをExcelで再現する練習をするのは、単にExcelの練習をしているのではありません。今後、仕事やプライベートで別のExcelマクロを作るときの参考となります。
練習をするときには、できるだけ細かい問題に分けて少しずつ作っていくのが鉄則です。細かく分割することによって、作ったマクロを別のプログラムで再利用することができます。
問題
このシステムを作るのに最低限必要なマクロ(正確にはプロシージャです。以下省略)は何個と考えられるか。
解説
与えられている条件からどんどん細かく分割していきましょう。問題文から必要とされる機能は大きく4つであることが分かります。
- 1~999の数値の場合は、番号を表示して音声案内をする
- 数字+マイナスの場合は、呼出番号を削除して詰める
- アスタリスク3つの場合は、呼出番号をすべて削除
- 数字+プラスの場合は、シートの切り替え
これらを作る前にあらかじめ実験しておきたいマクロは次の4つです。ブック、シート、セル範囲の取得は別にしておきたいですね。
- 表示用のブックを取得(ブックが無ければエラー)
- 入力するセルと出力するセルを取得
- 操作用Excelの呼出番号を表示用Excelへ転記する
- 音声案内をする
さらに、音声案内(マクロD)はライブラリを使用し、案内する呼出番号を100の位、10の位、1の位に分けること(例:345=300+40+5)、音声ファイルの存在確認をすること、音声ファイルを再生することの3つに分けます。
- 100の位、10の位、1の位を計算する
- 音声ファイルの存在確認
- 音声ファイルの再生
最後にこれらのマクロをつなげるメインルーチンを作ったら、とりあえず完成とします。
- セルD4に入力されたときにマクロを実行する
- 入力値によって振り分けをするメインルーチン
- フォーカスを常にセルD4にする
エラーの処理についてはキリがないのですが、表示用のExcelを開いていないときにはエラーメッセージを表示して即終了とします(最初にマクロAを呼び出す)。
6.補題
VBAはすべて、操作用のExcelファイルのシート内(シートモジュール)に格納します(参考:【初心者向け】マクロとは何か?Excel VBA基本の使い方を徹底解説します!動画解説付き)。
以下のコードは説明に必要な最低限のものを載せています。例外処理等のややこしいことは一切省いています。
(1)マクロA:ブックの取得
問題
「マクロA」として、表示用のExcelファイル(Workbook)を取得しなさい。ただし、取得できない場合はエラーメッセージを表示して終了しなさい。
解説
2つのブックを連携させるにはWorkbookの取得が必須となります。表示用のファイルを閉じた状態で「マクロA」を実行してエラーになれば正解です。
Function MacroA() As Workbook
On Error GoTo ErrHdl
Set MacroA = Workbooks("表示用.xlsx")
Exit Function
ErrHdl:
Set MacroA = Nothing
MsgBox "ファイルが開かれていません。"
End Function
(2)マクロB:セルを返す
問題
「マクロB」として、1の場合はセルD4(入力欄)、2の場合はセルB7(操作用の先頭)、3の場合は表示用の1枚目のシートのセルA3を返しなさい。
解説
はじめから入力または出力するセルの場所が分かっている場合は、それぞれのルーチンに記述するのではなく、セルを取得するルーチンまたは定数にしておいたほうが良いです。なお、表示用のセルは「マクロA」でブックを取得します。
(マクロBのSelectCaseの部分)
Select Case num
Case 1
Set MacroB = Range("D4")
Case 2
Set MacroB = Range("B7")
Case 3
Set wb = MacroA()
Set MacroB = wb.Sheets(1).Range("A3")
End Select
例えば、「MacroB(1)=5」を実行してセルD4に5が入力されたら正解です。
Sub test()
MacroB(1) = 5
End Sub
(3)マクロC:転記する
問題
「マクロC」として、操作用Excelのセル範囲B7:D7,B10:D10,B13:D13の数値を、表示用Excelのセル範囲A3:C5に転記しなさい。
解説
連動させるだけであればマクロを使う必要はありませんが、前述のとおり、外部のパソコンに表示させることを考えた場合、呼出番号を送受信するマクロが必要となります。それを前提として転記するマクロを作りましょう。
マクロBでそれぞれの先頭のセルを取得します。INTとMODとOFFSETで転記することができます。
(マクロCの転記の部分)
Set startcell1 = MacroB(2)
Set startcell2 = MacroB(3)
For i = 0 To 8
current_row = Int(i / 3)
current_col = i Mod 3
startcell2.Offset(current_row, current_col) _
= startcell1.Offset(current_row * 3, current_col)
Next
(4)マクロD:音声案内
問題
「マクロD」として、「ピンポーーン」の音声ファイルを再生しなさい。ただし、再生後にマクロを3秒間停止しなさい。
解説
音声ファイルを再生するには最低でも次の3つのコードが必要です。
- ライブラリ
- 音声ファイルの存在確認
- 音声ファイルの再生
まず、モジュールの先頭に次のコードを記述します。こんなものを覚えられるわけがないので、ネットからパクりましょう。
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _
(ByVal lpstrCommand As String, _
ByVal lpstrReturnString As String, _
ByVal uReturnLength As Long, _
ByVal hwndCallback As Long) As Long
音声ファイルのファイル名と拡張子でファイルの存在確認をし、秒数を渡して再生します。3秒間停止するのはピンポーーンが約3秒だからです。
Sub MacroD(num)
sec = 3
sound = MacroD2("pinpon", "mp3")
If sound <> "" Then Call MacroD3(sound, sec)
End Sub
ファイルが無ければエラーになるので存在確認をしておきます。
Function MacroD2(fname, ex)
sound = "(保存されているフォルダのパス)\" & fname & "." & ex
If Dir(sound) = "" Then
MsgBox sound & "がありません。"
MacroD2 = ""
Else
MacroD2 = sound
End If
End Function
MCIで再生するとともに、指定された秒数だけ待ちます。
Sub MacroD3(fname, sec)
mciSendString "Play " & fname, "", 0, 0
Application.Wait Now + TimeSerial(0, 0, sec)
End Sub
さらに、「マクロD」は1〜999の数値を受け取って、100の位と10の位と1の位に分けて、音声ファイルを探してピンポーーンの後に再生します。INTとMODを使います。
Sub MacroD(num)
Dim sound(4) As String
Dim sec
sec = Array(3, 1, 1, 0)
sound(0) = MacroD2("pinpon", "mp3")
If sound(0) = "" Then Exit Sub
If num >= 100 Then
sound(1) = MacroD2(Int(num / 100) * 100, "wav")
If sound(1) = "" Then Exit Sub
End If
If num Mod 100 >= 10 Then
sound(2) = MacroD2(Int((num Mod 100) / 10) * 10, "wav")
If sound(2) = "" Then Exit Sub
End If
sound(3) = MacroD2(num Mod 10, "wav")
If sound(3) = "" Then Exit Sub
For i = 0 To 3
If sound(i) <> "" Then Call MacroD3(sound(i), sec(i))
Next
End Sub
7.仕上げ
(1)番号の追加と呼び出し
1~999の番号を入力したときはそれを受け取って追加しますが、すでに表示されている場合は何もせずに終了します。
Set startcell = MacroB(2)
For i = 0 To 8
current_row = Int(i / 3)
current_col = i Mod 3
Set current_cell = startcell.Offset(current_row * 3, current_col)
If current_cell = num Then
Exit For
ElseIf current_cell = "" Then
current_cell = num
Exit For
End If
Next
さらに、マクロCで転記、マクロDにnumを渡して音声ファイルを再生します。
(2)番号の削除
「7-」のように数字+マイナスの形式で入力されたときは、いったん表示されている呼出番号を一次元配列に入れて保存するのと同時に、呼出番号をクリアします。
Dim a(8)
Set startcell = MacroB(2)
k = 6 - Int((num - 1) / 3) * 3 + (num - 1) Mod 3
For i = 0 To 8
current_row = Int(i / 3)
current_col = i Mod 3
Set current_cell = startcell.Offset(current_row * 3, current_col)
If i = k Then a(i) = "" Else a(i) = current_cell.Value
current_cell = ""
Next
ちなみに、kの数式は、789456123をそれぞれ012345678に変換する数式です。
配列の中に空白があればそれを詰めて、呼出番号を表示します。
cnt = 0
For i = 0 To 8
If a(i) <> "" Then
current_row = Int(cnt / 3)
current_col = cnt Mod 3
startcell.Offset(current_row * 3, current_col) = a(i)
cnt = cnt + 1
End If
Next
さらに、マクロCで転記します。
(3)すべての削除
「***」の場合はすべて削除ですが、さきほど呼出番号のクリアをしているのでそれと同じです。さらに、マクロCで転記します。
startcell.Offset(current_row * 3, current_col) = ""
(4)シートの切り替え
「7+」のように数字+プラスの形式で入力されたときは、シート番号を指定してシートを選択します。ただし、Sheets.Countを超えた番号の場合は終了します。
Sub Macro4(wb, num)
If num < 1 And num > wb.Sheets.Count Then Exit Sub
wb.Activate
wb.Sheets(num).Select
ThisWorkbook.Activate
End Sub
(5)メイン:正規表現で振り分け
4つの機能を作ったので、メインルーチンを作りましょう。まず、表示用のExcelを開いていなければ何もせずに終了します。
Sub Macro_main()
Dim wb As Workbook
Set wb = MacroA()
If wb Is Nothing Then Exit Sub
End Sub
セルD4が空白のときも終了します。終了しないと無限にこのマクロが呼び出されてしまいます。
Set rng = MacroB(1)
If rng = "" Then Exit Sub
入力された値を正規表現によって振り分けて、上記4つのマクロを呼び出します。もし、入力している途中で間違いに気づいた場合は、この正規表現に当てはまらない形式で入力すれば良いです(例えばスラッシュをつける)。
Dim RE
s = rng.Value
rng = ""
Set RE = CreateObject("VBScript.RegExp")
With RE
.IgnoreCase = False
.Global = True
.Pattern = "^\d{1,3}$"
If .Test(s) And s > 0 And MacroB(2).Offset(6, 2) = "" Then Call Macro1(CInt(s))
.Pattern = "^[1-9]\-$"
If .Test(s) Then Call Macro2(Left(s, 1))
.Pattern = "^\*\*\*$"
If .Test(s) Then Call Macro3
.Pattern = "^\d+\+$"
If .Test(s) Then Call Macro4(wb, CInt(s))
End With
Set RE = Nothing
(6)セルD4で固定する
セルD4から選択が外れたら強制的にセルD4に戻します。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MacroB(1).Select
End Sub
また、セルD4の値が入力された時にマクロを実行します。これで完成です。
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, MacroB(1)) Is Nothing Then Call Macro_main
End Sub
8.受付カードについて
受付カードを作ってラミネートをするのであれば、Wordの差し込み印刷(ラベル)をすれば良いです。
自動で発券をするのであれば、ボタンを押したら、自動で番号を1ずつ増やして印刷するマクロを作っても良いでしょう(簡単なのでコードは省略)。
9.さいごに
「既にある装置を作って何の役に立つのか?」
「Excelで作っても実用性が無いでしょ?」
アルゴリズムや計算問題が苦手な人に限ってこういう愚かなことを言うのですが、身の回りにあるものをアルゴリズムとしてとらえ、自分で作ってみることは情報処理の基本であり、情報処理の出発点です。
愚問を繰り返している暇があったら、まずExcelの勉強から始めてみてはいかがでしょうか?
解説は以上です。