はじめに
ふくぶちょ~です。バイト先とかのデータがExcelにほとんど集約されていたためExcelVBAを触ることにしました。普段はC++で競技プログラミングとかしかしていなかったのでなかなか大変でした。そのあたりについて軽く書いていこうと思います。仕様とかはあんまりわかんないのでそこらへんの説明は甘いと思いますがご勘弁を。
まずExcelVBAを使えるようにしましょう
普段マクロの作成をしていない人ならまずどうやってマクロを作成するのかすら知らない人も多いと思います。まず、Excelファイルの拡張子を確認してください。もしこの拡張子が.xlsxなら(おそらく一般的にはこの拡張子だと思います。)残念ながら使うことが出来ません。この拡張子を.xlsmにしましょう。やり方は名前を付けて保存を行うときにExcel マクロ有効ブックを選ぶだけです。
さて次ですがExcelを開いたときに下の画像のように開発というタブがありますか?もしなかった場合はもう一段階やらなくてはいけないことがあります。
ファイルのタブを押してもらうと一番左下あたりにオプションというものがあると思います。そこをクリックしてください。すると次のような画面が出てくると思います。そこでリボンのユーザー設定そして右上のところをメインタブにします。ではメインタブの開発にチェックを入れてください。そうするとExcelの画面上に開発のタブが出来ます。
さてでは開発タブを押してみましょう。そこのVisual Basicを開いてみてください。すると新しいウィンドウが。ここでマクロを作成することになります。
標準モジュール
最初は標準モジュールを挿入してみましょう。標準モジュールを作成したらその中に
Sub test()
End Sub
と入力してみてください。これでマクロが出来ました。ただしこのままでは何も行わないマクロです。そのためこのtestプロシージャ内に色々書き足していきましょう。今急に出てきたプロシージャとは複数の処理を一纏めにしたものという意味があります。
参考にさせていただいたプロシージャの意味を詳しく説明してくださっているサイト
デバッグ出力
これからマクロを作成するにあたって今この中身がどのような数値になっているかどうかチェックする必要があるみたいなことになると思います。その時に役に立つのがこのデバッグ出力です。そのためにまずはイミディエイトウィンドウを開きましょう。
すると一番下にウィンドウが開きます。ではモジュール内に以下のように記述してみてください。これを実行(F5キーを押すか上の緑の三角形をクリックか実行タブからマクロの実行をクリック)してみると下のウィンドウにちゃんと12345が出たと思います。これはこれから様々なものの表示に使えるので使っていってください。
Sub test()
Debug.Print 12345
End Sub
Excelのセルに関する入出力
まずExcelのデータに関する処理をするマクロなのでセル内の内容を読み取る、またはセル内にデータを書き込む処理が必要となります。そのためそれについて学習していきましょう。
コード | 説明 |
---|---|
Range("ここにセルの場所") | その場所のセルを指す |
Cells(i,j) | i行目j列目のセルを指す |
Sheets("ここにシート名") | そのシート名を持つシートを指す |
Sheets(i) | i番目のシートを指す |
実際の使い方は以下のようになります。ただし、以下のマクロを実行する時は2つ以上のシート、そしてシート名「Sheet2」のシートが必要です。
Sub test()
Range("A1") = 1 ' 今開いているシートのA1のセルに数値1を書き込む '
Range("B1") = "はろー" ' 今開いているシートのB1のセルに文字列「はろー」を書き込む '
Cells(3, 1) = 2 ' 今開いているシートのA3のセルに数値2を書き込む '
Cells(4, 1) = "こんにちは" ' 今開いているシートのA4のセルに数値2を書き込む '
Sheets("Sheet2").Range("A1") = 1 ' シート名「Sheet2」のA1のセルに数値1を書き込む '
Sheets(2).Range("B1") = "はろー" ' 2枚目のシートのB1のセルに文字列「はろー」を書き込む '
Sheets("Sheet2").Cells(3, 1) = 2 ' シート名「Sheet2」のA3のセルに数値2を書き込む '
Sheets(2).Cells(4, 1) = "こんにちは" ' 2枚目のシートのA4のセルに数値2を書き込む '
Dim tmp '変数の宣言。これについては次の項目で書きます。'
tmp = Range("E1") ' 今開いているシートのE1のセルの内容をtmpの中に入れる '
Debug.Print tmp ' tmpの内容をデバッグ出力 '
End Sub
変数
当然ながら処理の中でデータを一度どこかに保存して取り出すという操作が必要になってきます。そのような時にどこか適当なセルに値を入れておいて後で取り出すという操作でもいいのですがあまりきれいとは言えません。そのため変数を用意する必要があります。また、ExcelVBAにはデータの型がいくつかあります。この型によって扱えるデータの種類が変わってくるのです。だからその中でよく使うであろう型を紹介していきます。
型の種類 | 説明 |
---|---|
Long | 整数を扱う型であり-2,147,483,648~2,147,483,647の整数が使える |
String | 文字列を扱う型 |
Boolean | 真偽を扱う型でありTrueかFalseのどちらか |
Double | 実数を扱う型であり基本的に殆どの値を扱うことができるが誤差に注意 |
Variant | 何でもOK |
参考にさせていただいた型について詳しく書かれているサイト
何でもOKなら全部Variantでいいじゃんと言われればそれはそうとしか言えません。ただしマクロ作成者の混乱やマクロの誤作動の元になりうるのでそのデータの型が明らかな場合は型をVariantにしないほうがいいと思います。実際の書き方は以下のようになります。
Sub test()
Dim data1 As Long ' Long型の変数data1を宣言 '
Dim data2 As String ' String型の変数data2を宣言 '
Dim data3 As Boolean ' Boolean型の変数data3を宣言 '
Dim data4 As Double ' Double型の変数data4を宣言 '
Dim data5 As Variant ' Variant型の変数data5を宣言 '
Dim data6 ' Variant型の変数data6を宣言 As以降を省略するとVariant型に '
data1 = 5
data2 = "こんにちは"
data3 = False
data4 = 10.5
data5 = "さようなら"
data6 = 6
Dim data7 As Long
Dim data8 As Double
data7 = data1 * data4 ' 5*10.5=52.5だがdata7はLong型なので整数52に丸められる '
data8 = data1 * data4 ' data8はDouble型なのでそのまま52.5 '
Debug.Print data7
Debug.Print data8
End Sub
If文
条件分岐というのは絶対に使う場面があると思います。それができるのがこのIf文です。構文としては
If 条件文 Then
条件文が正しいときの処理
End If
If 条件文1 Then
条件文1が正しいときの処理
ElseIf 条件文2 Then
条件文1が正しくなく条件文2が正しいときの処理
ElseIf 条件文3 Then
条件文1,2が正しくなく条件文3が正しいときの処理
.
.
.
Else
すべての条件文が正しくないときの処理
End If
実際のコードは以下のようなものがあります。内容としてはA1のセルに入った数値をtmpに代入し100ならA2のセルを「満点」、それ以外なら空欄にする。その後評定をtmpによって分類してA3に表示するというものです。実際にA1のセル内に0~100までの整数を入れてみましょう。
Sub test()
Dim tmp As Long
tmp = Cells(1, 1)
If tmp = 100 Then
Cells(1, 2) = "満点"
Else
Cells(1, 2) = ""
End If
If tmp >= 100 Then
Cells(1, 3) = "評定10"
ElseIf tmp >= 90 Then
Cells(1, 3) = "評定9"
ElseIf tmp >= 80 Then
Cells(1, 3) = "評定8"
ElseIf tmp >= 70 Then
Cells(1, 3) = "評定7"
ElseIf tmp >= 60 Then
Cells(1, 3) = "評定6"
ElseIf tmp >= 50 Then
Cells(1, 3) = "評定5"
ElseIf tmp >= 40 Then
Cells(1, 3) = "評定4"
ElseIf tmp >= 30 Then
Cells(1, 3) = "評定3"
ElseIf tmp >= 20 Then
Cells(1, 3) = "評定2"
ElseIf tmp >= 10 Then
Cells(1, 3) = "評定1"
Else
Cells(1, 3) = "評定0"
End If
End Sub
For文
マクロを組む理由として手作業じゃ時間がかかりすぎるというものがあると思います。しかし前回の例では2つ目のIf文が多すぎてこれを書くのも大変でマクロ作成も面倒です。このような処理を上手く行えるのがループ処理です。そのループ処理はExcelVBAではFor文と呼ばれる文で行います。構文としては
変数が一回ごとに1ずつ大きくなるループ
For 変数 = 初期値 To これより大きいなら終了となる値
処理内容
Next
変数が一回ごとに加算値ずつ大きくなるループ
For 変数 = 初期値 To これより大きいなら終了となる値 Step 加算値
処理内容
Next
途中でループから抜けたいならExit Forを書きましょう
ではこのFor文を使って前回の例を書き直してみましょう。このコードでは前の例とは少し異なる条件式を用いています。具体的に言うと10点未満なら0、20点未満なら1...のようになっています。数値の変動がわからない時は適当なところにDebug.Printを書いてみるといいでしょう。
Sub test()
Dim tmp As Long
tmp = Cells(1, 1)
If tmp = 100 Then
Cells(1, 2) = "満点"
Else
Cells(1, 2) = ""
End If
Dim i As Long
For i = 1 To 11
If tmp < 10 * i Then
Cells(1, 3) = "評定" & i - 1 '文字列などの結合は&'
End If
Next
End Sub
だいぶスッキリしましたね。
実はこのIf文For文だけでかなりのことが出来ます。ぜひ色々やってみてください。これ以降は少し応用編っぽくなります。
配列
大量の変数を作りたい。そんな時に役に立つのがこの配列です。ほとんど普通の変数宣言と変わりません。以下は例。実は配列は必要ないんですけどね。
Sub test()
Dim tmp(100) As Long '100個の変数tmp(1)~tmp(100)を宣言'
Dim i As Long
Dim res As Long
For i=1 To 100
tmp(i)=i 'tmp(i)にiを代入'
Next
res=0
For i=1 To 100
res=res+tmp(i) 'resにtmp(i)を加算'
Next
Debug.Print res '1~100の和である5050が出力'
End Sub
構造体
例えば先生に関するデータをまとめているとしましょう。その時先生について必要なデータはたくさんあると思います。例えば名前、年齢、電話番号、住所...等。そのようなものを一緒に扱うことができるのがこの構造体です。言わば、自分で新しい型を作るものです。例として名前と年齢を一緒に持つ構造体を作ります。今までと違うこととして、この構造体の定義はプロシージャ内で行いません。
Type Person
name As String
age As Long
End Type
Sub test()
Dim teacher(50) As Person
teacher(1).name = "Tanaka"
teacher(1).age = 34
Debug.Print teacher(1).name
Debug.Print teacher(1).age
End Sub
他のプロシージャを呼ぶ
何かしらのプロシージャを作成している時に他のプロシージャを呼び出したい時があると思います。その時に使えるのがCallで以下のように使えます。
Call プロシージャ名
例 testプロシージャを実行すると「Nyan」が5回出力されます。
Sub test()
Dim i
For i = 1 To 5
Call test2
Next
End Sub
Sub test2()
Debug.Print "Nyan"
End Sub
この記事ではここまでしか紹介しません。では次はユーザーフォームの話です。
ユーザーフォーム
例えば名前を入れるとその人の情報を持ってきてくれるみたいな機能がほしいとします。それが可能なのがこのユーザーフォームです。以下のように挿入してみましょう。
ツールボックスは消してしまっても表示のツールボックスを押せばもう一度開くことが出来ます(一度この失敗して困ったので書いておきます。)。
さて、このユーザーフォーム内にツールボックスから色々入れることでよくあるフォームを作ることが出来ます。ラベルとテキストボックスとコマンドボタンを配置して次のようにしてみましょう。
ここから色々名前を変えたりフォントを変えたりするのですがその時にプロパティウィンドウを開いておくと便利です。そのため以下のようにして開きましょう。
さてプロパティを見ていきましょう。この中で高頻度で変えることとなるのはFont,TextAlign,Captionだと思います。覚えておきましょう。Fontはその通りでフォントであったり文字のサイズを変更できて、TextAlignではテキストが右揃えか中央揃えか左揃えを選べて、Captionではそのツールの中に書かれている文字を変えられます。一度その項目をクリックして編集してみてください。ものによってはクリックしたら右に何かしらボタンが現れて自分で書いて編集しなくてもいいものもあります。
頑張ってFontで文字のサイズを大きくしてTextAlienを2-fmTextAlienCenterにし、Captionを変更すると以下のようになります。なんかこれだけでそれっぽくなりました。
でもこれだけではただのハリボテです。この中身を実装していきましょう。各ツールをダブルクリックするとそれに対応したプロシージャが表示されます。ただし、全てのツールについてのプロシージャを並べるとどのツールとどのプロシージャが対応しているかわからなくなる可能性があります。そういう時はプロパティのオブジェクト名と見比べて確認しましょう。
以下のようにコードを編集しましょう。そして実行(マクロと同様にできる。)をするとこのユーザーフォームをテストする事ができます。ここでTextBox.ValueですがValueを書くことでテキストボックス内の情報を利用する事ができます。Excelシートに入力が反映されたら成功です。
ユーザーフォームの表示
まずはExcelファイルの開発からボタンを挿入してください。
新しいマクロができるのでUserForm1.Showを入力してください(名前が変わっていたらその入力フォーム名に対応した名前.Show)。
その後Excelファイルにあるボタンを押せば入力フォームが出ます。これで終わりですが少し変えるだけでもう少しいいものが作れます。CommandButton1_Clickプロシージャを以下のようにすれば人数を数えながら人間の情報を追加するようなものが作れます。
応用
作成された迷路の中の青色のプレイヤーを動かすミニゲームを作成してみた。これは1つのユーザーフォーム、2つのモジュールから出来ています。
- モジュール1
マップのどこにプレイヤーがいるかを発見するモジュール。いくつかの変数は他のモジュールでも利用可能なグローバル変数として宣言しています。
Public playerh As Long ' プレイヤーのいる行 '
Public playerw As Long ' プレイヤーのいる列 '
Public H As Long ' マップの行 '
Public W As Long ' マップの列 '
Sub 迷路()
H = 10
W = 15
Dim i As Long
Dim j As Long
For i = 1 To H
For j = 1 To W
If Cells(i, j).Interior.Color = RGB(68, 114, 196) Then ' 青色かどうか '
playerh = i
playerw = j
End If
Next
Next
End Sub
- モジュール2
Excelシート上にあるボタンを押した時に呼ばれるモジュール。
Sub ボタン1_Click()
Call 迷路 'モジュール1内の迷路プロシージャを呼ぶ'
UserForm1.Show 'ユーザーフォームを表示'
End Sub
- ユーザーフォーム関連のプロシージャ
RGB(0,0,0)は黒色(壁)、CodeIndex=0は無色(道)、RGB(68, 114, 196)は青(プレイヤー)。
Private Sub CommandButton1_Click() '上移動'
If pleyerh <> 1 And Cells(playerh - 1, playerw).Interior.Color <> RGB(0, 0, 0) Then
Cells(playerh, playerw).Interior.ColorIndex = 0
playerh = playerh - 1
Cells(playerh, playerw).Interior.Color = RGB(68, 114, 196)
End If
End Sub
Private Sub CommandButton2_Click() '左移動'
If pleyerw <> 1 And Cells(playerh, playerw - 1).Interior.Color <> RGB(0, 0, 0) Then
Cells(playerh, playerw).Interior.ColorIndex = 0
playerw = playerw - 1
Cells(playerh, playerw).Interior.Color = RGB(68, 114, 196)
End If
End Sub
Private Sub CommandButton3_Click() '右移動'
If pleyerw <> W And Cells(playerh, playerw + 1).Interior.Color <> RGB(0, 0, 0) Then
Cells(playerh, playerw).Interior.ColorIndex = 0
playerw = playerw + 1
Cells(playerh, playerw).Interior.Color = RGB(68, 114, 196)
End If
End Sub
Private Sub CommandButton4_Click() '下移動'
If pleyerh <> H And Cells(playerh + 1, playerw).Interior.Color <> RGB(0, 0, 0) Then
Cells(playerh, playerw).Interior.ColorIndex = 0
playerh = playerh + 1
Cells(playerh, playerw).Interior.Color = RGB(68, 114, 196)
End If
End Sub
おわりに
みんなもExcelVBAを使って業務改善!