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

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

初心者のためのExcel(エクセル)マクロVBA入門-成績表マクロの作成:ボタンとフォームの設置(イベント処理)


本題に入るその前に・・・

おわび


前回までの連載でコードに間違いがありました。出席番号をチェックするメソッドInputCheckの数字の範囲を確認する条件を間違ていました。


間違い:If CLng(shussekiNumber) < 0 And CLng(shussekiNumber) > 10 Then
正しい:If CLng(shussekiNumber) < 1 Or CLng(shussekiNumber) > 10 Then


でした。訂正してお詫びします。みなさんごめんなさい。0より小さくかつ10より大きいって・・・どういう条件だよ!ですね。大変失礼いたしました。1より小さくまたは10より大きいで、0番は含まないから1より小さくでした。

シートにフォームを設置する


今回はちょっと閑話休題っぽくなりますが、そもそものユーザーがマクロを動かすために使うボタンがありませんのでそこん所をちゃちゃっとやってしまいましょう。以前にもやっているので簡単なはずです。

[開発]タブ→[デザインモード]クリックして[挿入]→[Active Xコントロール]の中のボタンを選択します。

f:id:drumer2sh:20131017100433p:plain

ボタンをシートに設置しましょう。

f:id:drumer2sh:20131017100435p:plain

さらにボタンを右クリックして[プロパティ]を選択し、プロパティウィンドウを表示します。これのオブジェクト名とCaptionを変更してボタンの名前を変更します。名前はわかりやすいように[成績表出力]としました。

f:id:drumer2sh:20131017100436p:plain

これでボタンは完成です。ここから残りの出席番号を入力するテキスト入力フォームと、印刷オプションのチェックボタンを作成します。それぞれのオブジェクトの名前は

  • テキストフォームのオブジェクト名:txtSyussekiNumber
  • 印刷チェックボックスのオブジェクト名:chkbxPrintOutFlg

としています。なんとなくわかるでしょうか?

独自の命名規則を考えよう。


マクロプログラムを作る上で変数だったり、フォームだったり、シートオブジェクト、メソッドだったりと色々なものに「名前」を付けることが多くなります。プログラミングがうまい人は名づけ上手なんです。それは他の人が読んでこれがなんなのか?が良くわかるようなものになっているからです。ここで、あくまで私個人ではありますが採用している命名規則(名付けのルール)をご紹介しておきます。

  • 変数名は型の略称を最初に書き小文字から書き始めて後単語ごとに大文字表記する(LowerCamelCase)
    • lngHogeFuga
    • strTotoBubuなど
  • メソッド名は単語ごとに大文字で区切って表記する(UpperCamelCase)
    • InputCheck
    • OutputMainなど
  • オブジェクトはオブジェクトの種類の略を書き後は単語ごとに大文字で区切って表記する(LowerCamelCase)
    • shtMain
    • txtSyussekiNumberなど

このようにすれば、たとえばオブジェクトでもこれは何のオブジェクトで何を表しているのか?が名前を見るだけでわかりますので非常に読みやすくなります。

名前って長くてもいいの?


長くていいと私は考えます。読みにくいので略して短く書いた方が良いという意見もありますが、私は略すと結局何がなんなのか?という本来の名前付けの目的から外れてしまうと考えています。一応ですが、是非参考にしてみてください。

さて、全部のフォームを設置するとこうなります。

f:id:drumer2sh:20131017100432p:plain


これで基本的なユーザーが使いやすいフォームを設置しました。後は、ボタンが押された時のイベントを書きます。メインの処理は基本的に標準モジュールで書いていますよね?ですので、イベントではメインの処理を呼び出すだけにします。ボタンをダブルクリックして、イベントプロシージャを書いて行きます。

Option Explicit

Private Sub btnOutput_Click()
    
    'メインの処理を呼び出すだけ
    Call mdlMain.Main
    
End Sub

これだけです。基本的にはこれだけ。なんですが・・・これではボタンを押したらすぐにマクロが実行されてしまいます。

ユーザーの気持ちになろう


もし、間違って押してしまったりしたら・・・なんてこと思いませんか?きっと使う人ならあるはずです。ですので、そういうことも想定します。一旦確認の画面が出てくれると間違ってボタンを押しても、「いいえ」を押せばいいですよね?これもエクセルマクロだと簡単に実現できちゃいます。以前から使っているMsgBox関数とIf文を使います。

Option Explicit

Private Sub btnOutput_Click()
    
    Dim msgRet As Integer
    
    ' 成績表を出力しますか?
    msgRet = MsgBox(mdlDefine.MSG_CONFIRM_MACROSTART, vbYesNo + vbExclamation, mdlDefine.APP_TITLE)
    
    ' はいが押されたら・・・
    If msgRet = vbYes Then
    
        'メインの処理を呼び出すだけ
        Call mdlMain.Main
    
    End If
    
End Sub

こうなります。例によってmdlDefineにメッセージの内容は記載します。

mdlDefineの内容

Public Const MSG_CONFIRM_MACROSTART = "成績表を出力します。" + vbCrLf + "よろしいですか?"

この1文を追加しています。

VBAでは戻り値が欲しい場合は引数を()で囲う


MsgBox関数はただメッセージを表示して終了するだけの場合は、()はつけませんでした。しかし、今回は()で囲っています。VBAのルールでは、返り値を使わないとき、引数を括弧で囲みません。逆に今回のように「どのボタンをクリックしたか」を知るためには、MsgBox関数の返り値が必要になります。この場合は、引数を括弧で囲まなければなりません。

vbYesというのはVBAで用意されているキーワード定数です。「はい」が押された時にはMsgBoxは6という数字を返すのですが、これをIf文で・・・

If msgRet = 6 Then

なんて書いてしまうと・・・はて?6?6?ってなんだろ?となってしまいます。そういうのを防ぐためにちゃんとはいが押された場合にはvbYesという言葉(中身は6という数字)を使えるようになっているわけです。これなら「はい」が押された時とIf文を読むことができますよね。

さて、あとはお約束のエラー処理もちゃんと追加しておきましょう。ここでは想定されるエラーというのは、ありませんので、一般的な何かのエラーを処理できるように記載します。

Option Explicit

Private Sub btnOutput_Click()
'一般のエラーをキャッチする
On Error GoTo cmnErr

    Dim msgRet As Integer
    
    ' 成績表を出力しますか?
    msgRet = MsgBox(mdlDefine.MSG_CONFIRM_MACROSTART, vbYesNo + vbExclamation, mdlDefine.APP_TITLE)
    
    ' はいが押されたら・・・
    If msgRet = vbYes Then
    
        'メインの処理を呼び出すだけ
        Call mdlMain.Main
    
    End If
    
    'マクロ終了
    Exit Sub
    
cmnErr:
    MsgBox "エラーが発生しました" & vbCrLf & _
            "エラー番号:" & Err.Number & vbCrLf & _
            "エラーの種類:" & Err.Description, vbOKOnly + vbExclamation, _
            mdlDefine.ERROR_WINDOW_TITLE
    'マクロを終了する
    Exit Sub

End Sub

他にもユーザーが「気持ちよく」使えるような工夫はたくさんあると思います。皆さんも考えて是非色々と工夫してみてください。

フォームから値を取得する


さて、これでボタンを押すと・・・やっぱり出席番号を入力してくださいって言われますよね?当たり前ですが、そう「書いて」いるのでそうなります。ちゃんとフォームで入力した出席番号を使いたいですし、同じように出席番号を数字かどうかチェックしたりしたいわけです。さてでは設置した入力フォームから値を取り出して使えるようにしましょう。カッコよく言えば「入力フォームオブジェクトを操作して値を取得する」です!

mdlMainで・・・

Sub Main()
'一般のエラーをキャッチする
On Error GoTo cmnErr
    
    ' 必要な変数を作成する
    Dim shussekiNumber As String      ' 出席番号を格納する変数
    Dim name As String                ' 氏名
    Dim sansu As String               ' 算数点数
    Dim kokugo As String              ' 国語点数
    Dim rika As String                ' 理科点数
    Dim syakai As String              ' 社会点数
    Dim eigo As String                ' 英語点数
    
    Dim strErrMsg As String         ' 入力チェックの結果を格納する変数
    
    ' 出席番号を入力してもらう(ここで例外発生する!)
'    shussekiNumber = InputBox("出席番号を入力してください", "出席番号入力", 1)
    
    ' 出席番号をフォームから取得する
    shussekiNumber = Sheet1.txtSyussekiNumber.Value
    
    ' InputCheckメソッドを呼び出してエラーメッセージを格納する
    strErrMsg = InputCheck(shussekiNumber)

わかりやすく、必要のなくなったコードをコメントアウトしておきました。変わったのは変数shussekiNumberにテキストフォームの内容を取得しているところですね。大事なのはちゃんとシートオブジェクトから書くこと!です。今回はSheet1にしかフォームはありませんがものによってはフォームはいろんなシートに分散することもあります。ちゃんとどこにあるどのオブジェクトか?をちゃんと指定するようにしましょう。何度も言ってますが、

正しくオブジェクトを指定することがエクセルマクロマスターへの近道


です。ここをいい加減にしては絶対にいけません。基礎の基礎が大事ってことです。(byマドンナ古文)

これで、ユーザーが使うところと、実際の処理をリンクさせることができました。次はいよいよ、前回からの致命的なバグを直して処理の順番を変えて、さらに構造体を使い、もっともっとかっこいいマクロにします!答えは次回まで持越しです。。

今日はここまで。


かしこ