最終更新 2015.4.16
Excel 2013 「ファイル」→「オプション」→「リボンのユーザー設定」の右半分の欄 の「開発」にチェックを入れる。 「開発」→「コード:Visual Basic」で Visual Basic for Applications のウィンドウが表示される(以下 VBA のウィンドウと表記する)。
・VBA ウィンドウのプロジェクトエクスプローラが概念構造を表している。 ・Excel の 1 ファイル ( *.xlsm ) が 1 つのプロジェクトに対応する。 ・1 つのプロジェクトの中に Microsoft Excel Objects と 標準モジュールが並列の関係で存在する。 ・標準モジュールは 1 つ以上のモジュールファイルを含む。 1 つのモジュールは複数のマクロを含むことができる。 ・マクロは Sheet? や ThisWorkbook にも書ける。 しかし、Sheet? や ThisWorkbook の中に書いた関数は他のモジュールから 呼ぶことができない。 ゆえに、普通のプログラムは標準モジュールの中に書く。 Sheet? は Sheet に発生したイベントを処理する関数を書く。 ThisWorkbook は Book を開いたときに自動実行するマクロを書く。
< 画面構成 > ・「表示」→「イミディエイトウィンドウ」でイミディエイトウィンドウが表示される。 このウィンドウ内で命令を書いて enter を押すと即実行される。 プログラム実行中にエラーが発生して「デバッグ」を選んだとき、 イミディエイトウィンドウ内で「? 変数名 ↓」と打つと変数の内容が表示される。 ・「表示」→「プロジェクトエクスプローラ」でプロジェクトエクスプローラ画面を表示 < モジュール > ・「挿入」→「標準モジュール」で標準のジュールを新規作成 ・「ファイル」→「Module1の開放」でモジュール1 を削除 ・モジュールを選択するとき「ダブルクリック」する。「シングルクリック」ではない。 < エディタ > ・ヘルプが表示されている状態 (ex. dim a as in と打つ) は tab で補完 ・「表示」→「ツールバー」→「編集」のツールバーの中に、選択領域を全て コメントアウトするボタンがある。 ・領域を選択して tab を押すと、その領域全体に tab が適用される ・右端のスクロールバーの「▲」のすぐ上の部分を下へドラッグすると、 マルチウィンドウ ・モジュールが表示されている領域の左下のボタンで 「モジュール全体を表示」「一つのプロシージャのみを表示」を切り替える < 実行 > ・「実行」→「sub/ユーザーフォームの実行」で、そのときカーソルがある マクロを実行。 ・無限ループに陥ったときなど「ESC」でマクロの実行を中断する
Range("A1") = 123 数値
Range("A2") = "abc" 文字列
Range("A" & i) = 123 行を変数で指定
Range("A" + CStr(i)) = 123 + で連結するときは数値を文字列に変換するための CStr が必要
Cells(i, j) = 123 i は行 j は列
Cells(i, "B") = "acd" 列は文字列で指定してもよい。
・大文字小文字は区別しない。
・主な型は以下の通り
Variant 数値、文字列何でも入る
Integer 2 バイト整数 -32768 〜 32767
Long 4 バイト整数 -32768 〜 32767
Double 8 バイト実数
String 文字列
・変数の宣言
デフォルトで宣言不要 宣言しないとき Variant 型
モジュールの先頭(declaration 領域)で Option Explicit と書くと、
全ての変数に宣言が必要となる。
・宣言の方法 (要注意!!!)
Dim a As Integer, b As Double
Dim c, d As Long
~~ <----- c は Long ではなく Variant
各変数名の後に As Integer のような型が必要
As 型名 を省略したとき As Variant を省略したと見なされる。
上の例のとき、C 言語のように c は Long ではない。
As Variant が省略されていると見なされ、c は Variant 型となる。
変数の宣言場所は、各マクロの先頭でなくてもよい。
・定数
Const i As Integer = 12
・グローバル変数
モジュールは C 言語で言えば一つのファイルに相当する。
グローバル変数はモジュールの先頭(declaration 領域)で宣言する。
declaration 領域で Dim a As Integer のように宣言した
グローバル変数はそのモジュール内のみで共有される。
デフォルトで Private である。
モジュールにまたがるグローバル変数は Public a As Integer と宣言する。
Module1 の中で Public a As Integer と宣言すると、Module2 の中でも
変数 a が使える。
逆に Module2 の中でも Public a As Integer と宣言すると、
Module1 の a とは別の変数として扱われるので要注意。C とは異なる。
上記のような場合、Module1 で宣言された変数 a を使うには Module1.a
と表記する。
・Static a As Integer のように宣言すると、その変数の値はマクロの実行が
終わっても保持されるらしいが、初期化されるタイミングがややこしいので、
使わないほうが良いと思う。
・配列の宣言
Dim a(1 to 10) As Long のように上限と下限を指定するのがお勧め。
Dim a(10) と宣言すると、デフォルトでは a(0) 〜 a(10) の 11 個が使える。
配列の下限を指定するには option base
・配列のサイズを動的に決めたい場合
Dim buf()
Redim buf(1 to row_count, 1 to column_count)
For i = 10 to 1 Step -1
Exit For
Next i
Do While i < 10
Exit Do
Loop
Do While True
Exit Do
Loop
Do
Exit Do
Loop While i < 10
If a = 1 And b = 3 Then
x = "A"
ElseIf c = 1 Or c = 2 Then
x = "B"
Else
x = "C"
Endif
スペースとアンダーバーを右端に置く
goto LABEL LABEL:
Public Sub test1() End Sub Private Sub test2() End Sub 識別子 (Public or Private) を省略したとき、デフォルトは public。 test1() は他のモジュールから参照できるが、 test2() は同一モジュール内からしか参照できない。 Sheet1, ThisWorkbook, UserForm1 の中に書いた関数は他のモジュールから 呼ぶことができない。Public と書いても駄目である。
Sub Sub1(i As Integer, j As Integer)
i = i + 1
j = j * 2
Exit Sub ' <---- 途中で関数を抜けるとき
.......
End Sub
・参照渡しと値渡し 引数は、参照渡しがデフォルト Call sub1(i, j) あるいは sub1 i, j で参照渡し。Call を付けない場合、 sub1 (i), j とすると、i のみ値渡し。 sub1 (i), (j) とすると i, j ともに値渡し。 ・配列の渡し方 Dim array(1 to 10) As Long Call Sub2(i,array()) Sub Sub2(i as Long, array() As Long) ・型の一致 呼び出し側と、受け手側の型が一致しないとエラーが発生することがある。 ---------------- Dim a ' <---- 暗黙の型宣言により Variant 型 call sub1(a) ---------------- Sub sub1(i As Integer) End Sub ---------------- は Variant 型を Integer で受けるので、エラーが発生する。 ただし、サブルーチン側が Variant 型で受けるときは、 呼び出し側の変数の型は何であってもよい。
Function func1(i As Integer) As String
If i = 0 Then
func1 = "Err"
Exit Function
End If
If i > 3 Then
func1 = "A"
Else
func1 = "B"
EndIf
End Function
str = CStr(num) num = Val(str) Val ではなく CInt, CLng, CDbl を使ってもよい。
Trim(str) 左右の空白を切り落とし、途中の2個以上の連続空白は1個にする Right(str,3) 右側 3 文字を取り出す Left(str,2) 左側 3 文字を取り出す Mid(str,4,2) 4 文字目から 2 文字取り出す Len(str) 文字列の長さ InStr(str,"2") 文字列 "2" が含まれるとき何文字目か 見つからないとき 0 CStr(2) 数値 2 を文字列 "2" に変換 Space(12) 半角空白 12 個 Dim a as Variant a = Split(str, ",") a(0), a(1), .... に分割された文字列が入る。 a は Variant 型でないとエラーになる。 Split を実行すると a は自動的に配列になるようだ。
Range("A5").Select
Range("A5:B8").Select
Rows("4:4").Select
Columns("E:E").Select
Selection.Value = "abc"
Selection.Interior.Color = RGB(255, 255, 150)
VBA で用意されている関数と Excel が用意する関数は異なる。
Excel の関数を VBA で使うときは、以下のように書く。
Range("A1") = WorkSheetFunction.RandBetween(1, 20)
セル A1 に「 = RandBetween(1, 20) 」と書いて enter を押すのと同じ
Randomize 命令で乱数系列を設定する。
Rnd() 命令で乱数を取得する。
◆ 乱数系列の設定
Randomize システムタイマーから取得した値を seed として設定
Randomize(seed) seed を設定
◆ 乱数の取得
a = Rnd(seed) 乱数値は 0 以上 1 未満
1〜6 の乱数が得たいときは Int(Rnd() * 6) + 1
seed < 0 seed を設定
seed = 0 直前の値を返す
seed > 0 あるいは引数省略
直前に生成された乱数を seed とする
Excel の乱数の仕組みについては
このサイト が詳しい。
Randomize
a = Rnd
b = Rnd
c = Rnd
.....
とするのが一般的な使い方である。
しかし、偏りが激しい。1〜6 までの乱数を 120 回発生させたところ
1 が 12 回 6 が 26 回というケースがあった。
Rnd の前に引数なし Randomize を毎回実行すると偏りはなくなる。
毎回決まった乱数系列が欲しいときは
a = Rnd(-1.2)
b = Rnd
c = Rnd
.....
のように書く。
Randomize(1.2)
a = Rnd
b = Rnd
c = Rnd
.....
では同じ乱数系列にならない。Randomize(1.2) は現在の seed と
引数 1.2 をかけあわせて新しい seed を作る。それに対して
Rnd(-1.2) は seed を -1.2 のみから生成する。
◆ Randbetween の使用
実は、ワークシート関数 Randbetween を使った方が簡単である。
Range("A1") = WorksheetFunction.RandBetween(1, 20)
1 から 20 までの乱数を発生
他のプロジェクトに所属するモジュールを使用するときは VBA ウィンドウにおいて「ツール」→「参照設定」で使用したい プロジェクト名にチェックを入れる。 プロジェクト名のデフォルトは VBAProject である。参照先の ファイルは見分けやすい名前にするため、「ツール」→「VBAProject の プロパティ」でプロジェクト名を変更しておいたほうが良い。 参照先ファイルの path を変更すると参照できなくなる。
「開発」→「コントロール:挿入」→「ボタン(フォームコントロール)」 移動やサイズ変更のとき、alt を押すと、セル罫線に吸い付く。 ボタンを押したときに実行されるマクロを登録するとき、 「マクロシートに対する参照を指定してください」 というエラーが出ることがある。 マクロ名が a2, ab3, abc44 などのとき、このエラーが発生する。 ネットで調べると、セル名と重複するマクロ名はだめらしい。 Excel の列名は 3 桁まではありうる(4 桁は大丈夫)ので、 ローマ字 1 〜 3 字 + 数字 はダメである。 toi1 ---> toi_1 のように変更すると OK である。
ctrl + 1 で横の 2 つのセル結合
ctrl + 2 で縦の 2 つのセルを結合
を実現するプログラムは以下の通り。
Module1 の中に記述する。
Sub auto_open()
Application.OnKey "^1", "Ketsugou_yoko"
Application.OnKey "^2", "Ketsugou_tate"
End Sub
Sub Ketsugou_yoko()
Row = Selection.Row
Column = Selection.Column
cha1 = Chr(Asc("A") - 1 + Column)
cha2 = Chr(Asc("A") - 1 + Column + 1)
Range(cha1 + CStr(Row) + ":" + cha2 + CStr(Row)).Select
With Selection
.MergeCells = True
End With
End Sub
Sub Ketsugou_tate()
Row = Selection.Row
Column = Selection.Column
cha = Chr(Asc("A") - 1 + Column)
Range(cha + CStr(Row) + ":" + cha + CStr(Row + 1)).Select
With Selection
.MergeCells = True
End With