「制御構造」の考え方を意識したマクロの記述を学びます.まず,前回の条件分岐に引き続き,繰り返し処理の考え方と記法を学習します.そしてマクロにおける処理の流れが制御構造という考え方によって包括されることを,あわせて学習します.つぎに,単純な制御構造の記述を入れ子状に組み合わせることで,より複雑な制御構造を実現することが可能である事を,前回作成したサンプルマクロの拡張を通じて学習します.最後に次回への予習として,1つのプロシージャの中で別のプロシージャを呼び出して用いる「サブルーチン化」の考え方と記法を学習します.
1. 繰り返しの考え方
2. 制御構造を意識したマクロの作成
3. サブルーチン化の考え方
「繰り返し」の考え方と書き方を学習します.
繰り返しとは,一定の回数のあいだ同じ命令を繰り返し実行する処理のことです.たくさんのセルの書式を一括して変更するなど,多くの場面で必要とされます.
ここでは2の累乗を求めるマクロの作成を通して繰り返しの考え方を学習することにします.2の累乗とは,いわゆる2のn乗の計算結果のことです(このときのnを指数と呼びます).2の累乗は次のようになります.
n | 2n | 計算式 |
---|---|---|
0 | 1 | 1 |
1 | 2 | 1×2 |
2 | 4 | 1×2×2 |
3 | 8 | 1×2×2×2 |
4 | 16 | 1×2×2×2×2 |
5 | 32 | 1×2×2×2×2×2 |
... | ... | 1×2×2×2×2×2×...×2 |
この計算を以下のように,特定のセルに指数を入力してマクロを実行すると,別のセルに計算結果が表示されるようにマクロ化します(practice03.xls, Sheet1).
上記のマクロを実現する処理の手順を考えましょう.
2の累乗を求める計算式から,次のことが分かります.
ここから,2の累乗は以下の式をn回繰り返す処理として記述できることが分かります.
累乗 = 累乗*2 *ただし累乗の初期値は1とする
上記のような「〜をn回繰り返す」といった処理を記述するために,VBAではForステートメントが用意されています.Forステートメントの書式は以下の通りです.
Sub 繰り返しの書式 Dim i As Integer '繰り返し回数のカウント用変数 ' カウント用変数iの値が10になるまで命令Aを繰り返す For i = 1 To 10 命令A Next i End Sub
Forステートメントは「For A To B・・・Next〜」という書き方をします.Aではカウント用変数の初期値(数え始めの数)を代入文で設定します.上記の例では変数iに1が代入されているため,繰り返し回数は1から数え始めます.Bにはカウント用変数の上限を書きます.上記の例では実数で10が書かれています.さらに,Forステートメントの末尾には,Nextの次にカウント用変数の変数名を書きます.上記の例ではNext iとなっています.このように書くことによって,1回の繰り返しが終わるたびにカウント用変数の値が1増加します.したがって,上記の例ではiが1から10の間,すなわち10回の繰り返しがおこなわれることになります.
上記の処理手順をフローチャートで表現すると以下のようになります.
以下は2の累乗を求めるマクロを,Forステートメントを使って記述した例です.
Sub 累乗計算() Dim 累乗 As Long Dim n As Integer Dim i As Integer '繰り返し回数のカウント用変数 ' 指数を取得する n = Range("B2").Value ' 2の累乗を算出する 累乗 = 1 '累乗の初期値を設定する For i = 1 To n '指数に応じて累乗を行う 累乗 = 累乗 * 2 Next i ' 算出された計算結果を出力する Range("B3").Value = 累乗 End Sub
2の累乗を求めるマクロを改作して,ユーザーが指定した任意の整数aの累乗を求めるマクロを作成しましょう.ただしユーザーによる整数aの指定は,以下のように特定のセルへの入力によって行うことにします.
マクロのあらゆる処理手順は「制御構造」という原理に則って記述されます.ここでは制御構造の考え方を実際のマクロの作成を通して学習します.
制御構造とはマクロの記述に見られる,処理手順の一般的な構造を指します.VBAによるマクロに限らず,あらゆるプログラムの処理手順は3つの基本的な制御構造に則って記述されます.すなわち,あらゆる記述の大前提となる「順次」,そして前回学習した「条件分岐」,さらに先程学習した「繰り返し」です.VBAのマクロを含むあらゆるプログラムの処理手順は,これら3つの制御構造を組み合わせて記述されます.
複雑な処理を記述する場合,3つの制御構造を互いに入れ子状に組み合わせて用いることになります.たとえば,上の図の繰り返しの命令Aの部分は,単独の命令だけでなく,順次構造を持った複数の命令に置き換えることが出来ます.また,同様に条件分岐の命令A, 命令Bの部分には,繰り返しの制御構造を組み込むことが出来ます(以下の図を参照).3つの制御構造を互いに組み合わせることによって,あらゆる複雑な処理が表現できます.
このように3つの制御構造を自由に組み合わせることが出来るのは,いずれの制御構造も処理の入り口が1つで,処理の出口が1つだからです.すべての制御構造が「入り口1つ・出口1つ」であるという点は,1度に1つの処理しか行うことが出来ないコンピュータの動作の特徴を反映しています.どんなに複雑な処理であっても,「入り口1つ・出口1つ」の原則に則る限り,3つの制御構造を組み合わせることによって記述できるのです.
実際にマクロを作成しながら制御構造を理解しましょう.
ここでは前回作成した「テスト得点評価マクロ」の機能を拡張します.前回作成したマクロは,1人ひとりについての得点に応じた評価を判定します.しかし評価対象が増えた場合,いちいち手動で1人ひとりの判定を下すのは面倒です.そこで,名簿全員分の判定を自動的に下すように仕様を変更します(practice03.xls, Sheet2).
本題に入る前に,より単純な制御構造を持つマクロを作成してみます.ここでは先に「背景色初期化マクロ」を作成します.背景色初期化とは,セルの背景色を「色なし」に戻す作業を指します.評価を行った後で背景色の付いた名簿のすべてのセルに対し,背景色を自動的に初期状態,すなわち「色なし」に戻すマクロを作成します.
名簿は1人につき「氏名」「得点」の組み合わせで構成されます.ですから,1人分の背景色を初期化するには,
という2つの処理を実行します.これは最も基本的な「順次」の制御構造です.
名簿全員分の背景色初期化を行うためには,上記の処理を名簿全員分繰り返し行います.ですから,このマクロは結果的に,「繰り返し」の制御構造の中に「順次」の制御構造を組み込む形となります.
以下は上記の考え方に従って記述した「背景色初期化マクロ」のソースコードです.practice03.xlsのSheet2の名簿(26名分)を前提としています.
Sub 得点評価初期化() Dim i As Integer 'カウント用変数 ' 評価の結果を初期化する For i = 2 To 27 Cells(i, 1).Interior.ColorIndex = xlNone '氏名欄の背景色を色なしにする Cells(i, 2).Interior.ColorIndex = xlNone '得点欄の背景色を色なしにする Next i End Sub
上記のソースコードではCellsプロパティを利用してセルの位置を指定(すなわちRangeオブジェクトを取得)しています.Cellsプロパティは,以下の書式によってセルの位置を指定します.
Cells(行番号, 列番号)
たとえば,セルA1を指定するならば「Cells(1, 1)」,セルB5ならば「Cells(5, 2)」と記述します(列番号はA,B,C,D...の順に1,2,3,4...となる).
上のソースコードでは,Forステートメントのカウント用変数iの値をCellsプロパティの行番号の指定に連動させるように工夫をしています.すなわち,変数iをそのままCellsプロパティの行番号の指定にも流用しています.このことによって,「繰り返しが1回終わる→変数iの値が1増える→指定される行番号も1増える→結果的に次の行に処理が移行する」というサイクルが実現されます.
それでは本題に入ります.名簿全員分の得点評価を自動的に下すマクロを作成しましょう.
まず最初に,1人分の得点評価の仕方を決めておきます.ここでは前回作成したマクロに準じて,以下のようにします.
次にマクロ全体の処理の手順です.基本的には先程作成した「背景色初期化マクロ」と同様に,1人分の処理を名簿全員分繰り返せばいいはずです.ただし今回は,1人分の処理をする際には,得点に応じた処理の振り分けが必要となります.したがって,今回のマクロでは「繰り返し」の制御構造の中に「条件分岐」が組み込まれることになります.
以下は処理手順のアウトラインです.
・名簿全員分,以下の処理を繰り返す ・1人分の得点評価を下す 成績優秀者ならば ・セルの背景色を水色にする 赤点ならば ・セルの背景色をピンク色にする それ以外ならば ・セルの背景色を色なしにする
実際にソースコードを記述する際には,上記のアウトラインをより詳細に検討する必要があります.このマクロを実現するためには,上記のアウトラインでは表現されていない処理も必要となってきます.
以下は上記の構想に基づいて記述した,「テスト得点評価マクロ」のソースコードの1部です.コメントを手がかりとしながら,自分でマクロを完成させてみましょう(ここでは仮に成績優秀者を80点以上,赤点を40点以下としましょう.またColorIndexの値はそれぞれ水色34,ピンク色22です).
Sub テスト得点評価() Dim 得点 As Integer Dim i As Integer 'カウント用変数 ' テストの得点に対する評価を表示する For i = 2 To 27 ' テストの得点を取得する 得点 = Cells(i, 2).Value ' 得点に対する評価を背景色で示す If '成績優秀者の場合,背景色を水色にする ElseIf '赤点の場合,背景色をピンク色にする Else 'それら以外の場合,背景色を色なしにする End If Next i End Sub
上記のマクロを拡張して,特定のセル上に入力した基準に従ってA, B, C, Dを色分けするマクロを作成してみましょう(ColorIndexの値は黄色36,灰色15です).
最後に次回の作業の予習として「サブルーチン化」の考え方を学習します.
Excel VBAでは一つのプロシージャを記述する際に,別のプロシージャをあたかも一つの命令のように呼び出して実行することが出来ます.たとえば以下のコードウィンドウには3つのプロシージャが書かれています.1番上の「表項目欄の書式設定1」には,その下に書かれた2つのプロシージャの名前(「太字に設定」と「背景色を黄色に設定」)が書かれています.このように,他のプロシージャの名前を書くことによって,名前が書かれたプロシージャが呼び出され,その処理が実行されます.処理が終われば再び呼び出し元のプロシージャに戻り,次の行の命令の実行に移ります.
呼び出し元のプロシージャと呼び出される側のプロシージャの間に,記述の順序についての約束事はありません.上記の例ではたまたま呼び出し元の「表項目欄の書式設定1」が呼び出される側の「太字に設定」,「背景色を黄色に設定」よりも先に書かれていますが,これらの間の順序関係はどのようであっても構いません.とにかくプロシージャ名を正確に記述すれば,それがどこに書かれていようと,呼び出されて実行されます.
上述のように,複数のプロシージャの間で呼び出す/呼び出される関係が成立する場合,呼び出す側のプロシージャを「メインルーチン」,呼び出される側のプロシージャを「サブルーチン」と呼ぶことがあります.これはExcel VBAに限らず,あらゆるプログラミング全般について当てはまります.
メインルーチン/サブルーチンの関係を用いるメリットは,主に次の2点です.第1に,プロシージャの記述が長く複雑になった場合,その記述の一部をサブルーチンとして独立させることで,処理手順の全体像が整理され分かりやすくなります.この場合,記述の一部をサブルーチンとして独立させることを「サブルーチン化」と呼びます.第2に,しばしば行う処理をあらかじめプロシージャとして記述しておくことで,新しいプロシージャを作成する際に「部品」として利用することが出来ます.すなわち,新しいプロシージャ(メインルーチン)は,部品としてのプロシージャ(サブルーチン)の集まりとして組み立てられます.
テストの得点を手がかりに平均点,標準偏差,偏差値,偏差値に対する評価を自動的に出力する「テスト自動集計マクロ」を作成しましょう(practice03.xls, Sheet3).その際,平均点,標準偏差,偏差値の算出,および偏差値に対する評価の出力はそれぞれ独立したサブルーチンとして作成し,メインルーチンである「テスト自動集計マクロ」がすべてを統合するような形で作成しましょう.
今回の場合,メインルーチンはサブルーチンを呼び出すだけの役割を果たします.あらかじめサブルーチンの名前を決めた上で,以下のようにメインルーチンの記述を作成しておきます.
Sub テスト自動集計() ' テストの結果の集計を自動的に行う 平均点の算出 標準偏差の算出 偏差値の算出 偏差値評価の出力 End Sub
平均点及び標準偏差の算出には,ワークシート関数(Excelのワークシート上で,マクロではなく手作業で計算を行う際に利用する関数)を呼び出して利用します.平均点を算出する関数はAVERAGE関数,標準偏差を算出する関数はSTDEV関数としてそれぞれ用意されています.ワークシート関数を呼び出して利用する際には以下のように記述します.
Application.WorksheetFunction.関数名
AVERAGE関数およびSTDEV関数をワークシート上で利用する際には,計算の対象となる値の入っているセル範囲(複数のセルによって構成される範囲)を与える必要があります.たとえばB2からB27の値の平均値を算出するためには,平均値を表示したいセルに「=AVERAGE(B2:B27)」と記述します.このとき,関数が計算を行うために必要とする()内の値のことを「引数(ひきすう)」と呼びます.
VBAで上記のワークシート関数を呼び出して用いる際には,引数の記述の仕方が変わります.VBAにおいては,B2:B27のようなセル範囲はRangeオブジェクトとして扱われます.セル範囲を表すRangeオブジェクトの指定の仕方として最も一般的なのは,Rangeプロパティを用いて記述する方法です.たとえばB2からB27の範囲ならば「Range("B2:B27")」と記述します.このRangeプロパティの記述自体をまるごとワークシート関数の引数として記述します.
したがって,たとえばAVERAGE関数をVBA上で呼び出すには以下のように記述します.
Application.WorksheetFunction.Average(Range("B2:B27"))
上記の命令が実行されると,B2からB27の値の平均値が算出されます.関数やその他命令の実行によって算出される値のことを引数に対して「返値(かえりち)」と呼びます.Averageの返値を,たとえばB28に出力するためには,代入文によってRange("B28").Valueに代入します.
従って,平均点を算出するサブルーチンは以下のように記述することになります.
Sub 平均点の算出() ' 平均点を算出する Range("B28").Value = Application.WorksheetFunction.Average(Range("B2:B27")) End Sub
標準偏差を算出するサブルーチンも,上記と同様の手順で作成しましょう.
偏差値を算出する公式は「(得点ー平均点)/ 標準偏差×10+50」です.四則演算における()は,VBAでもそのまま()を記述することで有効となります.
1名分の偏差値を算出し,セルに出力するためには以下の処理手順が必要です.
名簿全員分の偏差値を算出するためには,上記の作業を人数分繰り返します.ただし1〜4の中で,1つだけ繰り返す必要のない処理があります(ヒント:あらかじめ1度だけやっておけばいいことです).考えてみましょう.
また,平均点,標準偏差,偏差値は小数値ですので,変数の宣言の際にはDouble型で宣言しましょう.
この部分は2.3の練習問題のマクロをそのまま応用すれば容易に作成できます.変更点は評価結果の表示の仕方です.2.3では背景色で示しましたが,今回はA, B, C, Dのいずれかを所定のセルに表示します.