こんにちは、.TAOです。普段何気なく使っているExcelは、多種多様な使い方ができる為に揶揄される事もありますが、とても便利なのは確かです。そんな「Excelを120%使い倒すべくマクロに挑戦してみよう!」という連載企画です。第2回目までは、「マクロは敷居の低いものなので、まずは使ってみよう。」という体でしたが、第3回目からはもう少し踏み込んだ内容となっています。VBAに興味のある方には、是非最後までお付き合いいただけると嬉しいです。
目次
1.実はとても重要な変数宣言
ワークシートとマクロとで明確に違う部分がこの変数です。マクロの中では、データを変数という箱に入れて扱うのが基本となります。Excelのマクロですので、ワークシートのセルを参照して変数の代わりに扱う事も出来ますが、コードが長くなるし現実的ではありません。
それに変数には、ある程度自由に変数名を決められる利点があります。ワークシートではセル番地A12とかD14とか言ったように参照して計算式を書きますよね。この場合参照しているセルの値が何を意味しているのかは、式を見ただけでは解りません。
その点VBAでは、変数に’平均’とか’合計’とか言った風に見て解りやすい名前を使えるので、式を見ただけで内容を把握しやすいのです。
この様に便利は変数ですが、VBAの標準設定では、事前に使用する変数の宣言をしなくても、一定のルールに沿ってコード中に現れた文字列を変数として自動で認識してくれる親切設計となっています。ですが、マクロが複雑になればなるほど宣言なしにコードを書いていると、後でエラー潰しや修正で泣きを見ることになります。ですからマクロを本格的にマスターしたいと考えるなら、変数宣言の重要性と変数の型については、しっかり把握しておきましょう。
変数宣言の強制「Option Explicit」
まずVBEのツール→オプションから「変数の宣言を強制する」にチェックを入れておきます。こうすることで、新規でモジュールを追加したときにコードウインドウの先頭に「Option Explicit」が追加され、宣言のない変数がコード内に出てくるとエラーになってくれます。タイピングミスで変数名を間違っていていた時にすぐ気づく事ができるのでエラーを特定するのが簡単になります。
変数の宣言と型
そして、宣言する時に重要になるのが「変数にどの型を割り当てるか」という点です。VBAでは取り扱うデータには様々な型式があり、それにそって値を扱う必要があります。ザックリ言えば、数値なのか文字列なのか、オブジェクトなのかといった具合で、文字列なのに数値として計算式を書いてしまえばエラーになるし、「09012345678」という電話番号を数値にしてしまうと「901234567」となって先頭の「0」が無くなってしまったりとかいった具合に、この辺はExcelの表でも同じことが言えますので想像できると思います。
型名 | 型 | 値の範囲 |
Integer | 整数型 | -32768~32768 |
Long | 倍長整数型 | -2147483648~2147483648 |
Single | 単密度浮動小数点型 | 負の値:-3.40E+38~-1.04E-45 正の値:1.40E-45~3.40E+38 |
Double | 倍密度浮動小数点型 | 負の値:-1.80E+308~-4.94E-324 正の値:4.94E-324~1.80E+308 |
Currency | 通貨型 | -922,337,203,685,477.5808 ~ 922,337,203,685,477.5807 |
String | 文字列型 | 任意の長さの文字列 |
Byte | バイト型 | 0~255の整数 |
Boolean | ブール型 | TrueまたはFalse |
Date | 日付型 | 100年1月1日0:00:00 ~9999年12月31日23:59:59 |
Object | オブジェクト | オブジェクト |
Variant | バリアント型 | すべてのデータ型 |
宣言に使う型はこれらの種類があり、変数に宣言する型によって収納できるデータが変わってきます。扱うデータがわからない時は As Variantとしてバリアント型を宣言しておけばOKですし、変数の型を指定しない場合もバリアント型として扱われます。ただし、先ほど説明したように文字列として入力したつもりが数字として処理されたりと、エラーの元となる場合もある事を認識しておく必要があります。
配列変数
変数の宣言は、
Dim 変数1 As 型名, 変数2(255) As 型名, 変数3(-255 To 255), 変数4(255,255,255)
といったように行の先頭にDim を書き、任意の変数名と変数の型をASで繋ぎます。宣言する変数は、,(半角のカンマ)で区切って書くことができますし、先頭にDim を入れて複数行書いてもOKです。ただ任意と書きましたが、使う事が出来ない予約語(Microsoft VB 言語リファレンスを参照)を指定するとコード記載時にエラーで弾かれます。
それとVBAで扱う関数やプロパティなどと同じ名前も紛らわしいので避けた方がよいでしょう。あと単純に規則に合わない文字列、例えば1Aとか数字から始まるものや、999などの数字だけといったモノも関数名として使えません。
また変数名の後ろに()をつけて配列サイズを指定する事で配列変数の宣言もできます。配列は最大値を指定する事で0から最大値までが割り当てられ、(最小値 To 最大値)を指定して部分範囲指定も可能です。
配列とは、Excelのシートを思い浮かべてもらうと分かりやすいと思います。Excelの表の上と左にアルファベットと数字が割り当てられていますよね。それにより、セル位置を指定できるように、配列変数の括弧内の数値で、データの収納位置を指定できるのです。第2回で説明したループで括弧内の数値を別の変数を使って指定するなど、データの扱いに幅が広がり格段に効率が上がります。
2.条件式IF文で流れを制御する
マクロ(プログラム)で重要な部分は計算と分岐です。その一つであるIF文をまずマスターしていきましょう。Excel関数にも=IF(条件式,Tlueなら~,Falseなら~)といった関数があり、使ったことがあると思います。考え方はザックリ同じと思ってよく、コードの書き方が違う点を理解すれば、直ぐに簡単なマクロを書けるようになります。
では、具体的なVBAでの条件文の代表的な形は以下のようになります。
Excelの関数と違って括弧で括らないし、条件と処理については行を変えて書くのが一般的で解りやすいと思います。シートのIF関数を使って複数の条件で処理を切り替えようとすると、関数の括弧が何重にも重なって解らなくなりますよね。その点マクロで書くとある程度解りやすく書く事が出来ますし、入れ子で条件式を書いても、どのIFがどのEND IFで完結するのかを気を付ければいいだけなので書きやすいと思います。
あと、IF~THEN・・・END IFはセットとしてコードに必要ですが、条件がFalseの時のコードElseとElseIfは無くてもOKです。
3.セルの選択Selectionオブジェクトを理解する
Excelをマクロで操作するのに欠かせないのがSelectionオブジェクトです。これを利用する事で、マクロからセルを指定するのではなく指定されたセルに対してマクロを作用させる事が可能となります。ここが重要なポイント。マクロを呼び出した時にシート上で範囲している部分をSelectionオブジェクトで調べて、得られたセル位置に対してマクロ処理を行える事で、任意のシート上の指定されたセルに対して活用できる汎用的なマクロを作る事ができるのです。
そんなSelectionオブジェクトを使って得られる値について簡単に説明すると、Excelシートで連続した複数のセルを選択した時の選択範囲や選択セル数についての値(プロパティ)を参照したり、直接値を変更したりといった事ができるのですが、具体的な具体例を見た方が解りやすいと思うので下のシートをみて下さい。
Selectionは選択された範囲を左上から右下までのセルに対して上の例の様に連続した番号を割り当てます。上の例だとC4の3列目4行目の位置が先頭として配列(1)が割り当てられています。最終行最終列の位置は順番に割り当てられた最終番号になるので、Selection(セル数)という様に、末尾番号をセル数で指定して.Columnで最終列を.Rowで最終行を参照しています。
選択しているセルを参照する方法としては、前回説明したActiveCellがありましたがActiveCellはその時入力できる1セルのプロパティを参照できるものなので、今回のように複数選択したセル全体のプロパティを見ることはできません。ですから上記の例でのActiveCellは、C4のみとなります。
下記にこの例を出力したマクロを載せておきますので、実際に試してみると理解が深まるかもしれません。VBEに新規モジュールを追加して、コピペして下さい。その後シートに戻り適当にセルを選択、「セレクションの説明」というマクロを実行します。すると選択範囲の情報が上記例のように表示されます。
Option Explicit Sub セレクションの説明() Dim 先頭列, 先頭行, 最終列, 最終行, 行数, 列数, セル数, i 先頭列 = Selection(1).Column 先頭行 = Selection(1).Row 最終列 = Selection(Selection.Count).Column 最終行 = Selection(Selection.Count).Row 行数 = Selection.Rows.Count 列数 = Selection.Columns.Count セル数 = Selection.Count For i = 1 To セル数 Cells(Selection(i).Row, Selection(i).Column).Value = i Next Cells(先頭行, 最終列 + 2).Value = 先頭列 Cells(先頭行, 最終列 + 3).Value = "先頭列 : Selection(1).Colum" Cells(先頭行 + 1, 最終列 + 2).Value = 先頭行 Cells(先頭行 + 1, 最終列 + 3).Value = "先頭行 : Selection(1).Row" Cells(先頭行 + 2, 最終列 + 2).Value = 最終列 Cells(先頭行 + 2, 最終列 + 3).Value = "最終列 : Selection(Selection.Count).Column" Cells(先頭行 + 3, 最終列 + 2).Value = 最終行 Cells(先頭行 + 3, 最終列 + 3).Value = "最終行 : Selection(Selection.Count).Row" Cells(先頭行 + 4, 最終列 + 2).Value = 行数 Cells(先頭行 + 4, 最終列 + 3).Value = "行数 : Selection.Rows.Count" Cells(先頭行 + 5, 最終列 + 2).Value = 列数 Cells(先頭行 + 5, 最終列 + 3).Value = "列数 : Selection.Columns.Count" Cells(先頭行 + 6, 最終列 + 2).Value = セル数 Cells(先頭行 + 6, 最終列 + 3).Value = "セル数:Selection.Count" End Sub
マクロを実行すると以下のように範囲指定されたセルに割り当てられた番号を入力、取得した値をその説明が出力されますので、選択範囲を色々変えながらマクロを動かしてみるとSlectionオブジェクトで得られる値について理解しやすいのではないでしょうか。
4.ちょっと実用的?なマクロを作ってみる
それでは、これまでのまとめとして連載3回目までの内容を盛り込んで実用的になりそうなマクロを作ってみましょう。使うのは、For~NextのループとIF~Thenの条件式、それと選択されているセルを調べるSelectionオブジェクトです。もちろんマクロの最初で使う変数の宣言もします。
どんなマクロを作るかと言うと、数式を含む連続したセルの参照先をそのままキープしたままで列を行に、行を列に並びを変換するマクロです。数式の参照先を絶対参照にしてあれば、Excelで列と行の並び変えをするコマンドがありますが、絶対参照ではない数式だと参照先が変わってしまい正しく計算されないといった経験があるのではないでしょうか。数が少ないなら一セルづつドラッグして並び変えても何とかなるでしょうが、数が多いとうんざります。
マクロを作るポイントとしては、任意に指定されたセルの選択範囲を調べ、選択されているセル数分ループして列なら行に、行なら列にセルを数式でコピー・貼り付けといったところでしょうか。もしチャレンジしてみたいという方は、自力で作ってみて下さい。それ程長いコードにはならないので、先ほど上げたポイントをクリア出来れば作れると思います。
面倒な方は、下記のコードをVBEにコピペして実行してみて下さい。マクロが何をしているのかは、注釈を参考にじっくり見れば理解はそう難しくないでしょう。
Sub 縦横変換() Dim Cst As Integer, Rst As Long, Ccnt As Long, Rcnt As Long Dim i As Long '選択されているセル位置を調べる Cst = Selection(1).Column '選択している先頭列番号 Rst = Selection(1).Row '選択している先頭行 Rcnt = Selection.Rows.Count '選択している行数 Ccnt = Selection.Columns.Count '選択している列数 '縦を横に変換 '選択している列数が1で、しかも選択している行数が1行以上だったら If Ccnt = 1 And Rcnt > 1 Then For i = 1 To Rcnt - 1 Cells(Rst, Cst + i).Formula = Cells(Rst + i, Cst).Formula Cells(Rst + i, Cst).Clear Next Range(Cells(Rst, Cst), Cells(Rst, Cst + Rcnt - 1)).Select End If '横を縦に変換 '選択している行数が1で、しかも選択している列数が1行以上だったら If Rcnt = 1 And Ccnt > 1 Then For i = 1 To Ccnt - 1 Cells(Rst + i, Cst).Formula = Cells(Rst, Cst + i).Formula Cells(Rst, Cst + i).Clear Next Range(Cells(Rst, Cst), Cells(Rst + Ccnt - 1, Cst)).Select End If End Sub
このマクロでは、選択範囲が縦一列なのか横一列なのかをIF文を使って判断して変換方向を分岐しています。また、縦横の並びを変えるといった動作なので、選択範囲のセル数が1以上で尚且つ一列又は一行でなければ作用しないよう条件を付加しています。そこを踏まえた上で、例えば先程のSelectionオブジェクトで使ったマクロの出力にSUM関数で合計を追加してマクロを実行すると下記の様に作用します。
このマクロは対象をマクロから指定していないので、ワークシート上のどこでも連続した列または行を任意に範囲指定してマクロを実行すると対象の縦横を変換します。このマクロを保存したファイルを開いた状態で別のファイルのワークシートからマクロを実行する方法も可能です。ただし、変換先のセルにデータがあったら有無を言わさず書き換えてしまうのでご注意下さいね。
今回のような汎用性のあるマクロには、ショートカットを割り当てて実行するといった方法が便利かもしれません。
いつもの手順でマクロのボタンからリストを表示。その後ショートカットを指定したいマクロを選んで「オプション」ボタンを押します。マクロ オプションで任意のショートカットキーを指定して「OK」。次からは、並び変えたいセルを選択してショートカットを押せばマクロが実行されます。
5.まとめ
どうでしたか?今回は第3回目という事で、より実用的なところまで突っ込んだ内容となっていましたが、説明しきれていない部分もあり歯痒いとこではあります。あまり詳しく書いてしまうと回りくどくなるし、説明が長くなりすぎると読んでいる方に申し訳なくて・・・。私の至らない部分は、この道のエキスパートの方々が有意義な情報をネットで配信してくれているので、そちらで情報を補完してもらえるとありがたいです。
とりあえずは、何となく今回を含めた連載を理解出来たなら、一般的なVBA入門として売られている本の8割位はクリア出来ていると思います。逆にこれまでの事を踏まえた上で、一般的なVBA入門書を読んで理解を深めるのも一考かもしれませんね。マクロをマスターしたいと考えるならば、そのVBAへの好奇心を実行に移してみる事だと思います。まずはここまでの事を足がかりに、自分なりに実践をしてみて下さい。実践して体験するトライアンドエラーが自らのスキルを高めてくれる事になりますから、臆せずやってみるのが一番です。なんだかんだ使用頻度の高いExcelですから、マクロは知っておいて損はありません。
ではまた、次回お会いしましょう。
コメント