初心者のためのExcelマクロ超入門(絶対できるVBA開発)

マクロがまったくわからない人のためにエクセルマクロやVBAについてできるだけわかりやすく書いています。Twitter:@shuhhohhey

初心者のためのExcel(エクセル)マクロVBA入門-成績表マクロの作成:エラーチェックその3

今回でエラーチェックを完成させます。さっそくですが、ファイルの存在チェックから。

Dir関数は存在チェックに便利!


テンプレートファイルが存在するか?を調べるにはDir関数という関数を使います。この関数は引数で指定したファイルが存在する場合に、ファイル名そのものを返し、ファイルがない場合は空文字("")を返します。
引数にはファイル名までのフルパスを指定してください。「フルパス」が分からない人は、<こちらexcelvba-25>を見てください。

つまり、Dir関数の値が空文字なら、そのファイルは存在しないということになります。
さっそくやってみましょう。まずはテンプレートファイルの場所と出力する個人成績表の場所をmdlDefineに記載しておきます。

mdlDefineにて

Public Const TEMPLATE_FILE_PATH = "C:\ExcelVBA\Template.xls"
Public Const SEISEKI_FOLDER_PATH = "C:\ExcelVBA\成績表\"


それから、この定数を使ってファイルの存在チェックをエラーチェックに書き込みます。


    ' 成績表テンプレートがない場合
    If Dir(mdlDefine.TEMPLATE_FILE_PATH) = "" Then
        '' テンプレートファイルがありません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG5
        
        InputCheck = False
        Exit Function
        
    End If

これで完了です。引数にmdlDefineで記載したパスを書いています。こう書いておけばもし、テンプレートファイルの場所が変わった時にはmdlDefineのパスを変えればいいだけなのでとても便利ですよね。

FileSystemObject(ファイルシステムオブジェクト)


はて?なんのこっちゃ?ということですが、VBAには基本の他にも色々と便利なオブジェクトが用意されています。オプションみたいなものです。しかし、これらのオプションは自分でちゃんとそのオプションを使うことを設定してあげないといけません。今回フォルダの存在を調べるのにとても便利なメソッドFolderExistsメソッドを使いたいのですが、そのメソッドはFileSystemObjectというオブジェクトが持っていてます。ファイル関連の便利な操作が色々と詰まっているオブジェクトです。

このオブジェクトは通常では使えないもので、自分でこのオブジェクトを使うために設定をしてあげないといけません。
VBEの[ツール]から[参照設定]をクリックします。


f:id:drumer2sh:20131030140836p:plain


するとこのように、たくさんのオプションのリストがあり、その中でもいくつかチェックがついていますね。
これは既に使っている標準のオプションです。
FileSystemObjectはこのチェックされている中にはありません。

Microsoft Scripting Runtime

というオプションに入っています。このオプションを探してチェックを付けてOKボタンを押しましょう。


f:id:drumer2sh:20131030140842p:plain



正確にはこのオプションのことを「ライブラリ」と呼んでいます。FileSystemObjectはMicrosoft Scripting Runtimeライブラリに入っているオブジェクトなのでこれを使うために参照設定を行った。ということです。
これでFileSystemObjectが使えるようになります。さっそく、以下のようにコード書きます。

Public Function InputCheck(ByRef strErrMsg As String) As Boolean
On Error GoTo cmnErr
    
    ' フォルダチェックのために使うオブジェクトを作成
    Dim objFileSys As New FileSystemObject
    

この1文で、FileSystemObjectを使うための変数objFileSysを作成しました。Newはオブジェクトのインスタンスを作成する時に使います。はて?インスタンス?となってしまうので、ここでは、、、

「オブジェクトの変数を使うためにはNewがいる。」

とだけを覚えておいてください。VBAならそれで十分です。
※もっとちゃんと具体的に知りたい場合は、オブジェクト指向系の本を読むとわかると思います。
 そのうちこのブログでもコラム程度に取り上げます。
 

後は、このオブジェクト変数を使ってチェックする式に入れるだけですね。

    ' 指定している保存先がない場合
    If Not objFileSys.FolderExists(mdlDefine.SEISEKI_FOLDER_PATH) Then
        '' 保存先が存在しません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG6
        
        InputCheck = False
        Exit Function
        
    End If


はい、簡単ですよね?FileSystemObjectを使うとフォルダの存在チェックが簡単にできてしまいます。これが、ライブラリを使う利点です。

ライブラリを使用する際の注意点


ライブラリはとても便利なのですが、すべてのエクセルに入っているわけではありません。つまり他のPCでは動かない可能性があるということです。今回使ったライブラリはすべてのExcelに最初から用意されているライブラリなので問題ないですが、バージョンによってはそうじゃないライブラリも存在します。また独自でダウンロードしたライブラリを使う場合にも注意が必要です。

使ったオブジェクトは破棄する

最終的なエラーチェックメソッドの全容です。


Option Explicit

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' 入力チェックのメソッド
' InputCheck
' 引数:なし
' 戻り値:Boolean
' エラーの場合はエラーメッセージを入れる
' エラーがない場合はFalseを返す
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function InputCheck(ByRef strErrMsg As String) As Boolean
On Error GoTo cmnErr
    
    ' フォルダチェックのために使うオブジェクトを作成
    Dim objFileSys As New FileSystemObject
    
    ' 出席番号が入力されてない場合
    If shtScore.txtSyussekiNumber.Value = "" Then
        '' 出席番号を入力してください。
        strErrMsg = mdlDefine.ERROR_MSG1
        
        InputCheck = False
        Exit Function
        
    End If
    
    ' 出席番号入力に数字以外を入力した場合
    If Not IsNumeric(shtScore.txtSyussekiNumber.Value) Then
        '' 出席番号が存在しません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG2
        
        InputCheck = False
        Exit Function
        
    End If
    
    ' 成績表の点数に数字以外が入っていた場合
    If Not CheckScore Then
        '' 成績表の点数が不正です。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG3
        
        InputCheck = False
        Exit Function
        
    End If
    
    ' 存在しない出席番号が入力された場合
    If shtScore.Range("A:A").Find(What:=shtScore.txtSyussekiNumber.Value) Is Nothing Then
        '' 出席番号が見つかりません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG4
        
        InputCheck = False
        Exit Function
        
    End If
    
    ' 成績表テンプレートがない場合
    If Dir(mdlDefine.TEMPLATE_FILE_PATH) = "" Then
        '' テンプレートファイルがありません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG5
        
        InputCheck = False
        Exit Function
        
    End If
    
    ' 指定している保存先がない場合
    If Not objFileSys.FolderExists(mdlDefine.SEISEKI_FOLDER_PATH) Then
        '' 保存先が存在しません。処理を終了します。
        strErrMsg = mdlDefine.ERROR_MSG6
        
        InputCheck = False
        Exit Function
        
    End If
    
    '個別で作ったオブジェクトは破棄する。
    Set objFileSys = Nothing
    
    ' エラーがないならとしてTrueを返す
    InputCheck = True
    
    Exit Function

cmnErr:
    MsgBox "エラーが発生しました" & vbCrLf & _
            "エラー番号:" & Err.Number & vbCrLf & _
            "エラーの種類:" & Err.Description, vbOKOnly + vbExclamation, _
            mdlDefine.ERROR_WINDOW_TITLE
    'マクロを終了する
    '個別で作ったオブジェクトは破棄する。
    Set objFileSys = Nothing
    Exit Function
End Function


成績表チェックするメソッド

''''''''''''''''''''''''''''''''''''''''''''''
' 成績表チェックするメソッド
' 戻り値:Boolean(True/False)
' 成績表の点数が数字じゃないならFalseを返す。
''''''''''''''''''''''''''''''''''''''''''''''
Private Function CheckScore() As Boolean

    Dim i As Long, j As Long
    Const COL_C = 3
    Const COL_G = 7
    Const SCOREDATA_START_ROW = 4
    
    '成績表をチェックする
    ' 4行目から成績表の最終行まで繰り返す
    For i = SCOREDATA_START_ROW To shtScore.Cells(Rows.Count, 1).End(xlUp).Row
        
        ' 算数(C列)から英語(G列)まで繰り返す
        For j = COL_C To COL_G
            
            ' 数字じゃなかったら・・・
            If Not IsNumeric(shtScore.Cells(i, j).Value) Then
                
                'Falseを返してメソッドを終わる
                CheckScore = False
                Exit Function
                
            End If
        
        Next
        
    Next
    
    '全部チェックして問題なければTrueを返す
    CheckScore = True

End Function


エラーチェックの方で最後にSet objFileSys = Nothingとしていますが、基本的にオブジェクトは使った後は破棄する。ということを覚えておきましょう。理由はずっと、オブジェクトを持っていると「遅くなるから」です。
専門的に言えば、参照しているメモリを解放してあげないとパフォーマンスが落ちる。と言ったところでしょうか?


これでエラーチェックメソッドは完成です。メインに組み込みます。エラーチェックはエラーならFalseを返すので・・・エラーでなければ次の処理をする。ということになります。


Sub Main()
'一般のエラーをキャッチする
On Error GoTo cmnErr
    
    Dim strErrMsg As String
    
    ' 事前の処理をする
    'Call mdlStartEnd.PreStart
    
    ' エラーのチェックをする
    '''' エラーならマクロを終了する
    If Not mdlErrorCheck.InputCheck(strErrMsg) Then
        
        ' エラーメッセージを表示する
         MsgBox strErrMsg, vbOKOnly + vbExclamation, mdlDefine.ERROR_WINDOW_TITLE
    Else
    
        ' 成績表を読み込む
        
        ' 成績表を出力する
    End If
    
    ' 事後の処理をする
    Call mdlStartEnd.PreEnd
    
    'マクロ終了
    Exit Sub
    
cmnErr:
    MsgBox "エラーが発生しました" & vbCrLf & _
            "エラー番号:" & Err.Number & vbCrLf & _
            "エラーの種類:" & Err.Description, vbOKOnly + vbExclamation, _
            mdlDefine.ERROR_WINDOW_TITLE
    'マクロを終了する
    Exit Sub

End Sub

エラーだったら、代入されているエラーメッセージを表示し、事後処理をして終了します。
エラーでなければ、成績表を出力する。
という処理になります。

これで、エラー処理は全部完了です!やっとこれからメインの処理を書いて行きます。


がんばりましょう!


今日はここまで。

かしこ