まず,今回使うサンプルファイルをダウンロードする.
人間とコンピュータが会話するようなインタラクティブなプログラムを作ってみよう.プログラムを実行する際,セルの値ではなく,毎回違う値を人が入力して使いたい場合がある.また,結果やメッセージをセルではなく画面に表示する方が効果的な場合もある.そのための仕組みとして,VBAにはInputBoxやMsgBoxという命令がある.
【例題1】おみくじプログラム
名前を聞いて「〇〇さんの運勢は◇◇です」と,画面に出力するプログラムを作れ.運勢は乱数でメッセージを選択すること.
乱数とは,値が出現する順番に規則性がなく,ばらばらの出現頻度をもつ数字の系列である.コンピュータはアルゴリズムに従って乱数を発生させるので,まったく規則性のない乱数を作ることはできないが,計算精度的にさほど問題のない疑似乱数と呼ばれる乱数を発生することができる.
ダウンロードしたprogram3.xlsmをダブルクリックする.次に「表示」メニューから「マクロ」を選び,マクロの表示から「おみくじ」という名前のマクロを「作成」する.
| Dim name As String, message As String |
| Dim r As Double |
| name = InputBox("あなたの名前は?") |
| Randomize |
| r = Rnd |
| If r > 0.8 Then |
| message = name & "さんの今日の運勢は" & range("a2") & "です" |
| ElseIf r > 0.6 Then |
| message = name & "さんの今日の運勢は" & range("a3") & "です" |
| ElseIf r > 0.4 Then |
| message = name & "さんの今日の運勢は" & range("a4") & "です" |
| ElseIf r > 0.2 Then |
| message = name & "さんの今日の運勢は" & range("a5") & "です" |
| Else |
| message = name & "さんの今日の運勢は" & range("a6") & "です" |
| End If |
| MsgBox message |
名前を覚えさせる文字型変数を name とすると,
name = InputBox("あなたの名前は?")
という命令で,画面に名前を聞くウィンドウを表示することができる.ダブルクォーテーション(")で囲まれた文字がウィンドウに表示される.人が文字を入力してOKボタンを押すと,入力した文字が name という変数に記憶される.

乱数を使うには,Rndという関数を使う.r = Rnd とすれば,変数 r に0から1までの乱数が設定される.ただし,このままだと r が毎回同じ数字になってしまう.なぜなら,コンピュータが発生させる乱数は,何かの数字(乱数の種という)を元に,ばらばらに見える数字が計算されているからである.randomize という命令を使うと,現在の時刻を元に乱数の種が設定されるので,毎回違った乱数を発生させることができる.そこで,乱数を発生させる前の行で randomize としている.
rは0から1までの数なので,この例題ではIf文で適当に5つに分けて運勢を決めている.If文の条件に使う数字を変えたり,運勢の文章を変えたり,好きに変更してよい.
メッセージを表示するには,MsgBoxという命令を使う.メッセージには String 型の変数を使う.名前を覚えさせた name という変数と "さんの今日の運勢は" のような文字列を連結するには & を使う.
message = name & "さんの今日の運勢は" & range("a2") & "です"
という命令で,nameが覚えている名前と"さんの今日の運勢は"という文字列とが連結され,さらに,A2セルに書かれた文字列と"です"という文字列が連結されて,messageという文字型変数に設定される.これを,MsgBox message という命令で画面に表示する.
エクセルの画面に戻り,表示メニューからマクロの表示→実行してみよう.MsgBox message の message がどのように設定されたか,よくわかると思う.何度か繰り返して実行し,違うメッセージが出ることを確認すること.また,表示されるメッセージはA2~A6セルを変更すれば,好きなメッセージにすることができる.自分なりのメッセージにしてみよう.
いくつか同じような種類のデータがある場合,一つ一つ別の名前の変数にしていると管理が大変になる.そういう場合は「配列」という仕組みを使う.例えば,aという名前の配列を使う場合,a(1),a(2),a(3),…として,配列名(要素番号)という形式で使う.
この配列になっている変数を使えば,Forループで繰り返し計算をするときに,
| For n = 1 to 10 |
| a(n) = n * n |
| Next n |
のように,要素番号も変数にすることができて便利.数学のベクトルや行列も,配列に入れて計算する.
【例題2】黄道十二星座プログラム
誕生日を入力すると,黄道十二星座を計算して表示するプログラムを作れ.「あなたは△△座です」と表示することにする.
プログラム解説
「表示」メニューから「マクロ」を選び,マクロの表示から「星座」という名前のマクロを「作成」する.
| Dim last(12) As Integer, stella(13) As String |
| Dim month As Integer, day As Integer |
| Dim k As Integer, seiza As String |
| ' 星座の各月における最終日 例:1月のやぎ座は19日まで |
| For k = 1 To 12 |
| last(k) = Cells(k+1,4) |
| Next k |
| ' 星座名 やぎ座は12月と1月があるので2回出てくる |
| For k = 1 To 13 |
| stella(k) = Cells(k+1,5) |
| Next k |
| month = InputBox("何月生まれですか?") |
| day = InputBox("生まれた日は何日ですか?") |
| ' 誕生日が各月における星座の最終日までかどうかを判定 |
| If day <= last(month) Then |
| seiza = stella(month) |
| Else |
| seiza = stella(month + 1) |
| End If |
| MsgBox "あなたは" & seiza & "です." |
1行目の変数宣言で,lastとstellaを配列として宣言している.last(12)とすることによって,last(3)とかlast(12)とかの要素を使うことができる.lastには整数を覚えさせ,stellaには文字列を覚えさせることを宣言している.
なお,このプログラムでは空行を使って構造がわかりやすくなるよう工夫している.また,各行のアポストロフィ(')以降はコメントとみなされ,プログラムが実行される際には無視されるので,自由に説明等を書くことができる.ここでは行の初めにアポストロフィを置いたのでその行全体が無視されるが,命令文の後にアポストロフィを置いて説明を書いても構わない.
2~3行目で4つの変数を宣言している.誕生月をmonth,誕生日をdayという変数(どちらも整数型)に覚えさせることにする.星座名をseizaという文字型変数に入れる.「星座の各月における~」の3行でlastに各月前半の星座名の最終日を,「星座名」という箇所からの3行で配列stellaに各星座名を,それぞれ覚えさせている.kはForループのカウンター変数で,次の部分を使ってエクセルシートのD列とE列から読み込んでいる.
配列の要素番号にも変数が使えるので,配列を使う場合にはこのようにForループと組み合わせて使うことが多い.例えばlast(k) = Cells(k+1,4)を,kが1~12まで変化させながら実行すると,最初はkが1なので,last(1)にCells(2,4)つまりD2セルの値が入る.次にkが2になるので,last(2)にCells(3,4)つまりD3セルの値が入る.最後はkが12になるので,last(12)にCells(13,4)つまりD13セルの値が入る.lastの要素番号と,覚えさせたいセルの行番号が一つずれているので,Cellsのカッコ内はk+1を使用している.
次のmonth=とday=の行で,生まれた月と日を入力させている.「誕生日が~」が星座の判定部分になる.判定方法は以下の通り.
何月生まれか(month)がわかれば,星座には2つの候補がある.例えば1月生まれの人(month = 1)は,「やぎ座のstella(1)」か「みずがめ座のstella(2)」になる.19日までなら「やぎ座」で,そうでなければ「みずがめ座」である.19という数字はlast(1)が覚えている.よって,生まれた日 day がlast(1)以下かどうかを判定し,last(1)以下ならstella(1)の「やぎ座」そうでなければstella(2)の「みずがめ座」とする.
これを一般化して1月以外でも使えるように month 月の場合について考える.dayが last(month) 以下かどうかを判定すればよいということがわかる.各月における最終日までなら stella(month) とし,そうでなければ次の順番の星座 stella(month+1) とすればよい.12月は21日までならいて座,それ以降はやぎ座になるので,12+1=13の要素が必要になる.そのためstella(13)としてやぎ座が設定されている.
エクセルの画面に戻り,表示メニューからマクロの表示を選び,「星座」を実行してみよう.正しい表示がされたらOK.最後に,このファイルを保存しておこう.
もし,名前を聞く画面や運勢を表示する小さなウィンドウの上部に表示される「Microsoft Excel」というタイトルも変更したい場合は,("表示されるメッセージ","タイトル")のようにすればいい.例えば,name = InputBox("あなたの名前は?","おみくじ")
名前を何も入力せずEnterキーを押した場合,名前が空欄のままプログラムが実行される.それを防ぐには,If name = "" Then と名前が空欄だった場合の処理をするのが親切.あるいは,入力部分をWhile~Wendという命令を使って名前が空欄以外になるまで繰り返すことも可能.Whileで設定した条件式が満たされている間,Wendまでを繰り返すことができる.例えば,
| While name = "" |
| name = InputBox("あなたの名前は?", "おみくじ") |
| Wend |
月や日を入力せずEnterキーを押した場合,エラーが表示されてプログラムが止まる.例題1の名前を聞く場合と同様,空欄だった場合の処理をした方がいい.さらに言えば,文字が入力されたり,負の数や小数や存在する月日より大きな数が入力された場合の対処も必要.このように,コンピュータと人間とのやりとりをするプログラム設計(ヒューマンインターフェイス)は,人間が思わぬ行動をすることがあるので難しい.
詳しくは説明しないが,例えば次のような方法がある.month=とday=の2行を次の13行に入れ替える.こうすれば数字しか入力できず,あり得ない月日だと再入力になる.興味がある人は調べてみよう.
| Dim flag As Boolean, checkStr As String |
| flag = True |
| Do While flag |
| month = Application.InputBox("何月生まれですか?", Type:=1) |
| day = Application.InputBox("生まれた日は何日ですか?", Type:=1) |
| checkStr = "2000/" & month & "/" & day |
| If IsDate(checkStr) Then |
| flag = False |
| Else |
| MsgBox "月日が間違っています.再入力してください." |
| End If |
| Range("g1") = "" |
| Loop |