VBAでよく使う処理まとめ

自分のためのメモ。
よく使う処理をまとめた。

## ファイル系

### フォルダ内の全ファイルを処理する

``` vb
Dim filePath As String
Dim fso, files As Object
DIm file As File

Set fso = CreateObject("Scripting.FileSystemObject")
Set files = fso.GetFolder(path).files

For Each file In files
  ' ファイルの処理
Next file
```

※Objectは、使い終わったら参照を切るためにNothingを入れると良さそう

```  vb
Set fso = Nothing
```

### 拡張子がExcelファイルではないファイルは処理を飛ばす

``` vb
Dim extentionPos As Long
' 「.」の位置を取得する
extentionPos = InStrRev(file, ".")
If extentionPos > 0 Then
  Dim extentionType As String
  extentionType = LCase(Mid(file, extentionPos + 1))
  If extentionType <> "xlsx" And extentionType <> "xls" Then
    GoTo FILE_CONTINUE
  End If
End If
…
FILE_CONTINUE:
  ' 飛ばした後の処理があればここに記述する
```

## ブック系

### 名前でワークブックを取得する

``` vb
Dim wb As Workbook
Set wb = Workbooks("xxx.xlsx")
```

※`xxx.xlsx`は開いている必要がある

### ワークブックをアクティブにする

上記で取得したワークブックをアクティブにする場合

``` vb
wb.Activate
```

マクロを動かしているブックをアクティブにする場合

``` vb
ThisWorkbook.Activate
```

### ブックのオープン、保存、クローズ

#### オープン

``` vb
Workbooks.Open(fileName:=file)
```

#### 保存

```  vb
wb.Save
```

#### クローズ

``` vb
wb.Close

' 保存しない場合
wb.Close SaveChanges:=False
```

## シート系

### シートのインデックスを取得する

``` vb
Dim xxSheetIndex As Integer
xxSheetIndex = Sheets("Sheet1").Index
```

### シートの最終行を取得する

``` vb
Dim sheetEndRow As Integer
sheetEndRow = Sheets("Sheet1").Cells(Rows.Count, 【データがある列】).End(xlUp).Row
```

## セル系

### CellsとRangeを変換する

#### Cells→Range
``` vb
Dim rangeStr As String
rangeStr = Cells(【行数】, 【列数】).Address
```

`Cells(1, 1).Address`の場合、"A1"がrangeStrに入る。

#### Range→Cells
``` vb
Dim rowNum, colNum As Integer
rowNum = Range("アドレス").Row
colNum = Range("アドレス").Column
```

`Range("A2")`の場合、rowNumには2、colNumには1が入る。

### セルを結合する

``` vb
Range("開始アドレス:終了アドレス").Merge
```

A1～A3を結合したい場合は、`Range("A1:A3").Merge`で結合できる。

### セルの文字色を赤にする

``` vb
Cells(【行数】, 【列数】).Font.ColorIndex = 3
```

※Range(アドレス)でもいけるはず

## その他

### if文

``` vb
If xxx = yyy Then
  ' 処理１
ElseIf zzz = "123"
  ' 処理２
Else
  ' 処理３
End If
```

同値チェックは`=`一つなので注意。  
不一致のチェックは、`If Not`か`If xxx <> fff`で行う。

### 検索

``` vb
Dim foundCell As Range, firstCell As Range
Set foundCell = sheet.Cells.Find(What:="検索文字")
' 見つかった場合
If (foundCell Is Nothing) = False Then
  ' 検索文字に一致したセルが見つかった場合の処理

  ' 見つかったセルをfirstCellに入れる
  Set firstCell = foundCell

  Do
    ' 次のセルを検索する
    Set foundCell = Cells.FildNext(foundCell)
    ' 次の検索一致セルが見つからなかった場合
    If (foundCell Is Nothing) = False Then
      Exit Do
    ElseIf foundCell.Address = firstCell.Address Then
      ' 次の検索一致セルが最初に見つけたものと同じだった場合は、ループを抜ける（一周したため）
      Exit Do
    Else
      ' 検索文字に一致したセルが見つかった場合の処理
    End If
  Loop
End If
```

### Subの呼び出し

``` vb
' xxxを呼び出す
Call xxx()

Sub xxx()
…
End Sub
```

### ファイルを切り替えないようにする

ファイルやブックを切り替えて処理するようなものだと、画面が切り替わるのが煩わしくなることがあるため、ScreenUpdatingをfalseにする。

``` vb
Application.ScreenUpdating = False
```

処理が終わった後にTrueに戻すのを忘れないように。忘れるとExcelのファイル操作ができない（多分画面に反映されていない状態になる）。

``` vb
Application.ScreenUpdating = True
```

### エラー処理

とりあえず小さいマクロだったらこれでいいかな、と思う。

``` vb
Sub xxx()

On Error GoTo Catch
  ' Sub xxxの処理を書く
Finally:
  ' 最後に絶対にやらないといけないことを書く
  ' 例）Application.ScreenUpdating = True
  ' 例）Set obj = Nothing
  Exit Sub
Catch:
  GoTo Finally

End Sub
```

### マクロが遅いときにやること

早くなるかはわからないけど、やると気休めくらいにはなる。

#### Sheets("シート名")をやめてインデックス指定にする

`Sheets(1)`のようにインデックスを指定して取得する。

#### Range("xx:yy").Columnを多用しない

列数が固定なら、`.Column`で取得しないで列数で指定する

#### 極力`.Select`を使わない

画面更新が入るため、遅くなるらしい。
そのため、例えば`Sheets(1).Cells(row, col)`のようにシートを指定して実装する。

## 参考

[Tipsfound Excel VBA Tips](https://www.tipsfound.com/vba/)
[Office TANAKA VBAコンテンツ](http://officetanaka.net/excel/vba/tips/)