和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ブックを現在開いているかチェックする関数

ある名前のブックを現在開いているかを確認する関数を紹介します。

Worksbooks(ブック名)でブックを指定するときに、
「インデックスが有効範囲にありません」エラーを回避するために使いますね。

やり方はとても単純です。
ブックを1つずつ見ていき、目的のブック名と一致しているブックがあるか調べます。

ソースコード

Function Isブックを開いている(判定ブック名 As String) As Boolean

    ' 開いているすべてのブックを走査
    Dim wb As Workbook
    For Each wb In Workbooks
    
        ' ブック名が一致したらTrueを返してExit
        If wb.Name = 判定ブック名 Then
            Isブックを開いている = True
            Exit Function
        End If
        
    Next
    
End Function

使い方

    If Isブックを開いている("商品マスタ.xlsx") = False Then
        MsgBox ("処理に必要なマスタが開かれていません。")
        Exit Sub
    End If

コードの解説

教本のような「コレクションに対するFor Each」ですね。


For Each で開いているすべてのブックを走査し、
ブック名が判定ブック名と一致したらTrueを返してExitします。

Exitせずにループが終わったら、一致したブックがなかったということで、
Booleanの初期値であるFalseが返るしくみです。


もし、この初期値の利用がイメージしづらかったら、関数の最後を

    Next

    Isブックを開いている = False
End Function

と書くと理解しやすいです。
For Each ~ Next をExitせずに突破出来たら、FalseにしてEndです。

エラーを利用した別の判定方法

お忙しい方は、↑の関数をコピペして早速使ってください。

お時間に余裕がある方は、↓のテクニックも読んでみてください。

エラーが発生するかどうかで判定を行う

冒頭の関数では、単純なループ処理で丁寧に判定しましたが、
実はループ処理を使わずに書くこともできます。

目的の「Workbooks(判定ブック名)」をいきなり指定してしまって、
それがエラーになるかどうかを調べる方法です。

Function Isブックを開いている(判定ブック名 As String) As Boolean
    On Error Resume Next ' この関数内ではエラーをスキップ
    
    ' 適当な変数に、目的のブックをセットしてみる
    Dim tmp As Workbook
    Set tmp = Workbooks(判定ブック名) ' ブックがなければこの文はスキップされる

    ' 変数へのセットがスキップされていないかで判定する
    If Not tmp Is Nothing Then
        Isブックを開いている = True
    End If
        
End Function

ブックが存在しない場合は、変数へのSetが「インデックスが有効範囲にありません」エラーになります。
それをOn Error Resume Nextでスキップしているわけですね。


スキップされた場合は、tmpは初期値であるNothingのままなので、
次のIf文でそこを判定しています。


なお、On Error Resume Next は、その関数の中だけで有効です。
「この関数を呼んだ後は、呼び出し元のエラーも無視されるようになる」ことはありません。


On Error Resume Next で、スキップしながら目的の処理をやってみて、
エラーが出るかどうかで状態を判定するのは、結構便利です。

いろいろな場面で活躍するので、テクニックとして覚えておきましょう。

さらに短く書ける

先ほどはエラーの活用を説明するために、丁寧な関数にしましたが、
せっかくループしなくて済むOn Error Resume Nextを使うのですから、
もっと短い行数で終わらせてみましょう。


まず、分かりやすい様に

    If Not tmp Is Nothing Then
        Isブックを開いている = True
    End If

こう書きましたが、これは

Isブックを開いている = Not tmp Is Nothing

こう書くこともできます。

「条件を満たすなら、結果はTrue」は、
「結果 = 条件を満たすかどうか」と書けますからね。

中身が1本しかないIf文は、慣れたらこっちで書きましょう。
単純な処理はなるべく短い行数で書いて、その分複雑な処理を丁寧に書くと、コードが読みやすくなります。


あとは、一時変数tmpも消すと、最終的にはこのコードになります。

Function Isブックを開いている(判定ブック名 As String) As Boolean
    On Error Resume Next
    Isブックを開いている = Not Workbooks(判定ブック名) Is Nothing
End Function

短い!

どっちの書き方がいいの?

どちらも一長一短で、ケースバイケースです。


1万回呼び出す関数なら、行数が短い方が、処理が速くていいかもしれません。

でも、今回の「ブック名」の判定は、マクロのスタート時にIf文で1回使う程度のことが多いので、速度は考えない方が良いですね。


あとで関数を書き替えたり、コピペして別の関数に使いたい場合は、
丁寧にループ処理を書いておいた方が便利です。


例えば、ブック名には、「日報0401」「日報0402」や、「売上データ202001」など、
識別用のパラメータ(日付とか)がついているやつも結構ありますよね?

この「ブック名の部分一致を判定する」関数は、
「丁寧なループで作った関数」のIf ~ Then部分を、

If wb.Name = 判定ブック名 Then
' ↓書き換え
If InStr(wb.Name, 判定ブック接頭名) = 1 Then

このように書き換えるだけで作成できます。


エラー技の方は、こういった活用はできません。


コピペして別の関数を作るメリットの方が大きそうなので、
今回は冒頭の丁寧なループ処理関数がおすすめです。


惜しくも不採用となってしまいましたが、
On Error Resume Next でスキップしながらやりたい処理をやってみて、
エラーが出るかどうかを関数で試すのは結構便利です。

いろいろな場面で活躍するので、テクニックとして覚えておきましょう。