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

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

プログラムを設計する(クラス、標準、Excel Objects)-Excel(エクセル)マクロ上級者への道

f:id:drumer2sh:20131004154711j:plain

さて、たまには初心者向けじゃなくて上級者になりたい。ちょっとはプログラミングわかってきたよ。的な人に向けて少し難しいお話でもしましょう。と思い上級者への道としました。初心者の皆様ごめんなさい。わからなくても、今回はまったく気にする必要ありません。

きれいなプログラムとは?


あくまで私の考えなのですが、Excelマクロで言う所のきれいなプログラムとは・・・

あるべきところに、処理が書かれているプログラム


です。あるべきところとは、イベントは当然Excel Objectsに書かれますが、メインの処理は標準へ、また共通処理はクラス化モジュール。など、処理によってそれぞれ書く場所を使い分けることです。こうすると一定の品質をある程度維持することができます。
私がやっている処理の分け方を例にすると。。。

  • イベントは各シートオブジェクト内で書くが処理は標準に書く
  • エラー、メッセージ、ファイル処理、DBアクセスなどはクラス化
  • 標準モジュールでも処理によりモジュールを分ける

この3つは大体やっています。エラー処理なんかは特にクラス化した方が良いもので、これをすることでVBAで煩雑なエラー処理をまるでフレームワークのように同じ記述で対応できます。
また、クラス化できないような処理もライブラリとして標準モジュールに分けて書いておくことで、どのマクロでも使いまわすことができるようになります。

マクロ基本構成


非常に簡単にですが、イベントから処理をどう分けるか?をちょっとだけ。

単純にボタンが押された時に何かしらの処理を行うマクロを仮定します。
まずはSheet1のオブジェクト内でイベントプロシージャが走るので。。。

Private Sub btnObject_Click()
On Error GoTo hErr
    
    '標準モジュールを呼ぶだけ
    Call moduleMain.PrcMain

    Exit Sub

hErr:
    Call objErr.ThrowError
    Call objPreMacro.ClosingMacro
End Sub

イベント内はこれだけです。標準モジュールのメイン処理をCallして終了。エラー処理は後述しますが、エラークラスを作成し、その処理通りにしていますが、このイベントプロシージャに最終的に処理は戻ってきますので、エラーを投げるのはこの最初のプロシージャになります。

続いて標準モジュール・・・

Pubilc Sub PrcMain()
On Error GoTo hErr
Const cnstPRC_NAME = "PrcMain"
    
    'マクロが始まったら最初にする共通処理
    Call objPreMacro.StartUpMacro
    
    'メインの処理をこちらに書いておき・・・
    
    '必要なら別の標準モジュールを呼ぶ
    Call modulePrc1.PrcHogeHoge
    
    'マクロが終わったら最後にする共通処理
    Call objPreMacro.ClosingMacro

    Exit Sub

hErr:
    Call objErr.SetError(cnstMODULE_NAME, cnstPRC_NAME)
    Call objPreMacro.ClosingMacro
End Sub


ここで実際の処理を行います。こうすることで、イベントとその処理を完全に分けることができました。さて、コメントを見ていただきたいのですが、最初と最後にobjPreMacro.StartUpMacroとobjPreMacro.ClosingMacroがあります。これはマクロをスタートするときにお決まりにする処理があったりしますよね?例えば、ボタンが押されないように非活性にしたり、画面更新をなしにしたり、そういった処理をクラスモジュールにまとめるわけです。例えばこんな感じで。


「clsPreMacro」というクラスモジュールを追加します。

Option Explicit

Private Const cnstCLS_NAME = "clsPreMacro"

Public Sub StartUpMacro()

    ' ScreenUpdatingをFalseにしたり、オブジェクトを非活性にしたり


End Sub

Public Sub ClosingMacro()

    ' StartUpMacroでやったことを元に戻す。


End Sub


というようにして、あとは共通の変数として変数定義用のモジュールを標準モジュールで作成し、たとえば、

Option Explicit

Public objPreMacro As New clsPreMacro
Public objErr As New clsError

とでもしておけば、どの標準モジュールでも使用が可能です。エラー処理も同じようにクラスで出来ているので、同じように宣言することでどの標準モジュールでもエラー処理が可能ですし、同じ処理を何度も何度も書く必要がなくなります。
エラークラスは詳しい処理は書きませんが、要するにSetErrorでエラーをキャッチしてメッセージをセットし、最後のThrowErrorメソッドでエラーを表示する。ということをしています。
こうしておけば、あとはいくらプロシージャを作っても、同じ処理を最初と最後に書くだけでエラー処理を考える必要がなくなります。

Public Sub プロシージャ名
On Error GoTo hErr
Const cnstPRC_NAME = "プロシージャ名"


    'この間に処理を書く


Err:
    Call objErr.SetError(cnstMODULE_NAME, cnstPRC_NAME )
    Call objPreMacro.ClosingMacro
End Sub

とすれば、いいわけです。

大事なのは書く前にプログラムを「設計」すること


あくまでこれは私の「処理の分け方」ですが、他にも処理を分ける方法はいくらでもあります。どのように分けるか?つまりプログラムを「設計」するか?は考えるあなた次第です。もちろん、私の考え方を参考にしてもらって構いませんが、色々なやり方を考えてみてください。ポイントは。。。

  • できるだけ処理を単位で分ける。
  • 一度書いたら同じコードは2度と書かなくて済むように。
  • 常に同じような書式で書けること
  • 再利用ができるように

このあたりに気を付けて書いていくと良いと思います。新しいマクロを組むたびに「再利用」できるコードやモジュールが増えているように是非、いきなりコードを書かないでプログラムを「設計」してみてください!


以上です。



かしこ