この数年で、VBAのクラスモジュールについて書かれた日本語書籍や、Webページが増えてきました。
拙著『いちばんやさしいExcel VBAの教本』執筆時のレビューで大変お世話になった、thomさんのブログではシンプルな例を使ってクラスモジュールについて解説されています。
こちらの記事でご紹介した連載では、本当に少しずつ少しずつ、スモールステップで解説が行われています。
しかしクラスモジュールを使うためには、複数のモジュール・プロシージャが必要でそれなりの量のコードを書く必要があり、その解説はどうしても結構なボリュームになります。そのためクラスモジュールを使ってみたいと思いながらも、一歩目を踏み出せない方が、まだまだいらっしゃるのではないかと想像しています。
クラスモジュールの便利さ・メリットを簡単に実感していただくために、コード量のできるだけ少ないサンプルを考えてみました。
イベント処理を、複数のシートで共通化するためにクラスモジュールを使う例です。
「3.4.3 共通イベント処理クラス」で紹介されているコードと考え方は同じですが、よりシンプルな形にして、実務で使えそうかも、と感じていただけそうな処理にしました。
書かなければいけないコードは、
' クラスモジュール「DataValidation」だけです。
Public WithEvents TargetSheet As Excel.WorksheetPrivate Sub TargetSheet_Deactivate()
If TargetSheet.Range("A1").Value = "" Then
TargetSheet.Select
Range("A1").Select
MsgBox TargetSheet.Name & "シートのA1セルには必ずデータを入力してください。"
End If
End Sub' 標準モジュール(Sheet1シート・Sheet2シートが必ず存在すること)
Private HandlSheet1 As VBAProject.DataValidation
Private HandlSheet2 As VBAProject.DataValidationSub AUTO_OPEN()
Set HandlSheet1 = New VBAProject.DataValidation
Set HandlSheet1.TargetSheet = VBAProject.Sheet1Set HandlSheet2 = New VBAProject.DataValidation
Set HandlSheet2.TargetSheet = VBAProject.Sheet2
End Sub
シートモジュールのイベントプロシージャを使う場合の課題
先日シートモジュールのイベントプロシージャを使った自動入力チェックをご紹介しました。
この方法で複数のシートで同じ入力チェックを行いたいという場合、各シートモジュールに同じイベントプロシージャを複製しなければならないという課題が発生します。
何らかの修正が入ったときには、複製したイベントプロシージャに、同じ修正が必要になります。
クラスモジュールを使うと、こういった課題も解決できます。
下図のようにワークシートが3枚存在しているときに、
Sheet1シートとSheet2シートで、A1セルにデータが入力されているかを、シートがアクティブでなくなったときにチェックする機能を、クラスモジュールを使って実装してみます。
DataValidationクラスモジュール
まずはVBEのメニュー[挿入]-[クラスモジュール]から、クラスモジュールを挿入後、プロパティウィンドウでモジュール名を「DataValidation」に変更して、
以下のコードを書きます。
Public WithEvents TargetSheet As Excel.Worksheet
Private Sub TargetSheet_Deactivate()If TargetSheet.Range("A1").Value = "" Then
TargetSheet.Select
Range("A1").Select
MsgBox TargetSheet.Name & "シートのA1セルには必ずデータを入力してください。"
End If
End Sub
画像で見ると下図のような状態です。
クラスモジュールの名前はもちろん自由に決めて構いませんが、他のチェック・検証も行う機能が将来追加されることを想定して「DataValidation」としました。
DataValidationクラスモジュールに書いたコードの解説
イベントを扱いたいので、WithEventsキーワードも使って、Worksheet型のグローバル変数TargetSheetを宣言しています。
Public WithEvents TargetSheet As Excel.Worksheet
このTargetSheetが、DataValidationオブジェクトのプロパティになります。
この変数名も、もちろん自由に決めて構いませんが、Excelに用意されているイベントプロシージャで処理対象を表すオブジェクトを示す引数の名前はTargetとなっていることが多く、今回はワークシートを処理対象とするのでTargetにSheetを付加した「TargetSheet」という名前にしました。
ここは、
Public WithEvents TargetSheet As Worksheet
と書いてもOKなのですが、Excelに元々用意されているWorksheetオブジェクト型であることを明確にするために、Asの後ろをライブラリ名「Excel.」から書いています。
このTargetSheetが、アクティブでなくなったときに行う処理を書くイベントプロシージャ「TargetSheet_Deactivate」の中身は、先日ご紹介したWorksheet_Deactivateイベントプロシージャと、ほとんど同じです。
違うのは、Meキーワードを使っていた箇所が、オブジェクト変数TargetSheetになっている点です。
If TargetSheet.Range("A1").Value = "" Then
TargetSheet.Select
Range("A1").Select
MsgBox TargetSheet.Name & "シートのA1セルには必ずデータを入力してください。"
DataValidationクラスモジュールに必要なコードはこれだけです。
標準モジュール
つづいて、上記の手順でクラスモジュールに作成したDataValidationオブジェクトを利用する、標準モジュールです。
上図のように3枚のワークシートのオブジェクト名が、デフォルトのSheet1・Sheet2・Sheet3のままであるときに、Sheet1とSheet2でA1セルにデータが入力されているかチェックする例とします。
標準モジュールを挿入して以下のコードを書きます。
Private HandlSheet1 As VBAProject.DataValidation
Private HandlSheet2 As VBAProject.DataValidation
Sub AUTO_OPEN()
Set HandlSheet1 = New VBAProject.DataValidation
Set HandlSheet1.TargetSheet = VBAProject.Sheet1
Set HandlSheet2.TargetSheet = VBAProject.Sheet2
End Sub
画像で見ると下図のような状態です。
標準モジュールに書いたコードの解説
先ほどクラスモジュールで定義したDataValidation型の、モジュールレベルのオブジェクト変数を宣言します。
Private HandlSheet1 As VBAProject.DataValidation
Private HandlSheet2 As VBAProject.DataValidation
この変数名も、もちろん自由に決めて構いませんが、Sheet1シート・Sheet2シートを扱うための変数ですから、「HandlSheet1」「HandlSheet2」としました。
ここは、
Private HandlSheet1 As DataValidation
Private HandlSheet2 As DataValidation
と書いてもOKですが、DataValidationオブジェクトが、Excelに元々用意されているオブジェクトではないことを明確にするために、Asの後ろを「VBAProject.」から書いています。
ブックが開かれたときに自動的に実行されるAUTO_OPENマクロ内で、これらのモジュールレベル変数をインスタンス化して、
Set HandlSheet1 = New VBAProject.DataValidation
Set HandlSheet2 = New VBAProject.DataValidation
DataValidationオブジェクトのTargetSheetプロパティに、このブックのSheet1オブジェクト・Sheet2オブジェクトをセットしています。
Set HandlSheet1.TargetSheet = VBAProject.Sheet1
Set HandlSheet2.TargetSheet = VBAProject.Sheet2
サンプルの確認方法
マクロが有効な形式でブックを保存し、VBA Projectのコンパイルをしてから、テストしましょう。
この記事からコピペをしてコンパイルエラーが出た場合、クラスモジュールの名前を「DataValidation」に変更していないケースが多いはずですから、プロパティウィンドウでオブジェクト名を正しく変更しましょう。
コンパイルが通ったら、AUTO_OPENマクロを実行してから、A1セルのデータ有無によって挙動が変化するか確認しましょう。
Sheet1・Sheet2の両方ともA1セルが空白のときにテストすると、Excelが落ちたりフリーズしたりするはずですからご注意ください。
A1セルにデータが入力されている場合
Sheet1シートのA1セルに適当なデータを入力してから、Sheet2を選択しましょう。この場合、A1セルにデータが入力されているので
「Sheet1シートのA1セルには必ずデータを入力してください。」
メッセージは表示されません。
A1セルにデータが入力されていない場合
つづいて、Sheet2シートA1セルにデータが入力されていない状態で、他のシートを選択してみましょう。
今度は、
「Sheet2シートのA1セルには必ずデータを入力してください。」
とメッセージが表示され、A1セルが選択されます。
Sheet1でもA1セルのデータを削除して、他のシートを選択しようとすれば、
「Sheet1シートのA1セルには必ずデータを入力してください。」
メッセージが表示されますが、Sheet3では入力チェックを行っていませんから、A1セルが空白でもそのようなメッセージは表示されません。
Sheet3シートでも入力チェックしたい場合
Sheet3シートでも同様の入力チェックを行いたい場合は、標準モジュールに、
Private HandlSheet3 As VBAProject.DataValidation
とモジュールレベル変数を宣言して、AUTO_OPENマクロに、
Set HandlSheet3 = New VBAProject.DataValidation
Set HandlSheet3.TargetSheet = VBAProject.Sheet3
を追加してから、AUTO_OPENマクロを再度実行してください。
クラスモジュールにインベント処理をまとめるメリット
例えば、チェックするセルを変更したい場合、各シートモジュールのイベントプロシージャを使っていると、全イベントプロシージャを修正する必要がありますけれど、クラスモジュールを使っている場合、クラスモジュール内のTargetSheet_Deactivateプロシージャ1つを修正するだけで済みます。
ここではA1セルの入力チェックだけを行っていますが、他にチェックしたい項目が出てきたときにも、クラスモジュール内にだけコードを書けば済むケースが多いはずです。
クラスモジュールを使わずに、各シートのシートモジュールにイベントプロシージャを作った場合、各シートモジュールを調べなければ、どのシートにイベントプロシージャが存在するかわからないのに対し、クラスモジュールを使って共通化していれば、標準モジュールを見れば、どのシートで入力チェックが行われるのかも簡単にわかります。
クラスモジュールの学習を始めた方へ 2019-02-10追記
thomさんが、クラスモジュールを使うメリットにもついても触れた、クラスモジュールの学習を始めた方向けの記事を書いてくださっています。
オブジェクト指向はコードを整理整頓する技術であり、それが根本の目的と言っても過言ではない。
オブジェクト指向の恩恵は、コードを読んで理解し、メンテナンスする際に初めて実感できるだろう。
クラスモジュールを使用するにはプロシージャの分割やモジュールレベル変数、プロシージャ間の値の引き渡し等の前提知識が必要となる。それらの知識が無い場合はまずそこから学習が必要である。
プログラミングの基礎を身に着けるために一旦他の言語に手を出してみるというのも良い経験になると思う。
最終更新日時:2019-02-20 16:08
Home » エクセルマクロ・Excel VBAの使い方 » クラスモジュールのメリットをイベント処理共通化で体験するサンプル