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

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

初心者のためのExcel(エクセル)マクロVBA入門-成績表マクロの作成:成績表を読み込む

こっからどんどん難しくなると思いますが、ついてこれない場合でもこんな感じなのかーと言うくらいに思ってくれてもいいです。要するにどう考えてどう作っているのか?ということを感覚的に理解してもらえると嬉しいです。

成績表を取り込む変数を作成する

成績表には点数の他にも、出席番号、氏名、コメントコードなどがありますね。
それらをすべてまとめてた成績表変数として作成します。これにはユーザー定義型の変数を使います。ちょっとややこしいですが、科目と点数も自由になるようにしておきましょう。前回作ったKamokuのユーザー定義も使います。


mdlDefineにて以下のように書きます。

' 科目のユーザー定義型
Private Type Kamoku

    kamokuName As String            '科目名
    score As Variant                '点数

End Type
    
' 成績表変数
Public Type Seiseki
    
    '出席番号
    skNum As String
    ' 氏名
    simei As String
    ' コメントコード
    cmntCode As String
    
    ' 科目と点数配列
    arryKamoku() As Kamoku
    
End Type

Public personalScoreData As Seiseki

ユーザー定義型が2つあります。科目のユーザー定義型と成績表型といいましょうか。この2つで成績表という大きな枠組みを持っています。成績表には以下の変数がありますね。

  • 出席番号
  • 氏名
  • コメントコード
  • 科目と点数の配列(Kamoku型の配列)

以上です。ユーザー定義型のすごいところはこのようにユーザー定義型が別のユーザー定義型を変数に持つことができるという点です。関係的にも成績表という情報は科目と点数の情報を科目ごとに配列で管理している。という言い方になります。


成績表
 | 
 | 
  - 科目と点数の配列

という関係です。そして最後に具体的な変数をSeiseki型で作成しています。
では成績表を読み込みます。成績表を読み込むにはズバリ!Find関数を使って読み込みます。

Find関数を使え。


出席番号は重複することはないということ、VLOOKUPよりも値が取りやすいという理由でFind関数を使っています。何度も関数実行するより一旦行を取得してから、Cellsプロパティで点数を参照する方が効率的ということもあります。
もちろんVLOOKUPを使っても不正解ではありません。動けば正解です。ですが、楽して効率的に書く。ということも目標にするとFindの方が良いですね。
またVLOOKUPですと普通に使うと検索した結果がない場合に例外エラーになってしまいます。FindはNothingが入るだけです。VLOOKUPでも例外にしない裏技もあるにはありますが、無理して使わなくても良いかな?と思います。
Findは検索結果のRangeオブジェクトを返してくれますので、あとはそこのRowプロパティを見れば入力した出席番号が実際のシートの何行目に位置しているのかが分かります。後はそこの値のオブジェクトを正しく指定してあげればいいだけです。
前置き長くてすいません。とっととコードに移ります。

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 成績表を読み込むメソッド
' InputScore
' 引数:なし
' 戻り値:なし
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Sub InputScore()
On Error GoTo cmnErr
    
    Const kamokuRow = 3     ' 科目名の行
    Const KamokuCol = 3     ' 科目名の列開始
    Const KamokuCol2 = 7    ' 科目名の列最後
    
    Dim rngSeiseki As Range
    Dim i As Long, cnt As Long
    
    ' Findで成績表を特定する
    Set rngSeiseki = shtScore.Range("A:A").Find(What:=CLng(shtScore.txtSyussekiNumber.Value))
    
    ' 成績表情報を読み込む(変数に代入する)
    
    ' 出席番号
    personalScoreData.skNum = shtScore.txtSyussekiNumber.Value
    
    ' 氏名
    personalScoreData.simei = shtScore.Cells(rngSeiseki.Row, "B").Value
    
    '配列インデックス
    cnt = 0
    
    ' 成績表を読み込む
    For i = KamokuCol To KamokuCol2
        
        ReDim Preserve personalScoreData.arryKamoku(cnt)
        personalScoreData.arryKamoku(cnt).kamokuName = shtScore.Cells(kamokuRow, i).Value
        personalScoreData.arryKamoku(cnt).score = shtScore.Cells(rngSeiseki.Row, i).Value
        
        cnt = cnt + 1
        
    Next
    
    ' コメントコードを読み込む
    personalScoreData.cmntCode = shtScore.Cells(rngSeiseki.Row, "H").Value
    
    Exit Sub
    
cmnErr:
    MsgBox "エラーが発生しました" & vbCrLf & _
            "エラー番号:" & Err.number & vbCrLf & _
            "エラーの種類:" & Err.Description, vbOKOnly + vbExclamation, _
            mdlDefine.ERROR_WINDOW_TITLE
    'マクロを終了する
    Exit Sub
End Sub

どこで何をしているのか?ということですが、最初と最後はいつも通りですね。
Constのところでは、行と列の定数値を設定しています。読み込む列や行が変わった場合はここを変更すればいいわけです。このように定数にしておくと実際のマクロのロジック部分に手を入れることがないので、変更後に起こるコードの記述エラーの可能性を抑えることができるのです。

Dim以下でお決まりの変数の作成です。Findの結果を格納する変数と、繰り返しで使うカウンタ用の変数を作成しています。

成績表の検索はA列のみで行います。Constで作成した範囲の定数が入っていますね。Find関数を使って出席番号を数値にキャストして引数としています。いつもならこの後にIf文でNothingかどうか?を調べるのですが、その必要は今回に限ってはいりません。なぜならそのチェックは既に事前に行っているからです。今回のように事前に想定できるエラーをチェックしておくことで実際の処理の時にロジックを省くことができます。

後はmdlDefineで作った変数にそれぞれの値を代入しているだけです。
大事なのは右辺です。この右辺のオブジェクトの指定の仕方をしっかりと参考にしてください。

これで読み込みは完了です。後はmdlMainから呼び出してあげましょう。

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
    
        ' 成績表を読み込む
        Call mdlInputScore.InputScore
        
        ' 成績表を出力する
    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

いつも通りCallステートメントで呼び出しているだけです。簡単ですね。

さて、いよいよ大詰めですね。次回でこの成績表マクロは完成すると思います。
わからないところはいつでも質問ください。コメントでもいいです。
後、こんな風にもできませんか?でもいいです。どんどんみなさんと一緒に勉強していきましょう!


今日はここまで!

かしこ