
photo credit: jjbers Former Manchester Parkade (Manchester, Connecticut) via photopin (license)
みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。
「初心者でもわかるエクセルVBAのクラスモジュール」についてシリーズでお伝えしています。
前回の記事はこちらです。

Property Letプロシージャの使い方をお伝えしました。
これで、クラスの作り方とPropertyプロシージャの使い方の超基本部分は抑えられたかなと思います。
が、作ってきたのはエクセル表の1行分を表すクラスです。
複数行をクラスを活かして扱うにはどうしたらよいでしょうか。
ということで、今回からコレクションの特性を持つクラスの作り方を目指していきますので、もうしばらくお付き合いください。
まず今回ですが、その前準備として、エクセルVBAでクラスのインスタンス生成時にデータを簡単に格納するメソッドを作る方法をお伝えします。
では、行ってみましょう!
前回までのおさらい
では、前回までのおさらいからです。
以下のようなエクセル表があります。
この1行分のデータを表すクラスPersonを作成したのですが、それをクラスモジュールに記述したのが以下のコードです。
Private id_ As String Public FirstName As String Public Gender As String Public Birthday As Date Public Sub Greet() MsgBox Me.FirstName & "です、こんにちは!" End Sub Public Property Get IsMale() As Boolean IsMale = (Me.Gender = "male") End Property Public Property Let Id(ByVal newId As String) If id_ <> "" Then Debug.Print "Idは上書きすることはできません" Else id_ = newId End If End Property
上記コードにより、クラスに以下のメンバーを追加しています。
- FirstNameプロパティ、Genderプロパティ、Birthdayプロパティはパブリック変数によるプロパティ
- IdプロパティはProperty Letプロシージャにより、一度だけその値をプライベート変数id_にセットができます
- IsMaleプロパティはProperty Getプロシージャによる読み取り専用のプロパティです
- メソッドはGreetという挨拶代わりのメソッドですね
それを検証するための、Subプロシージャは以下の標準モジュールModule1に記載されています。
Sub MySub() Dim p As Person: Set p = New Person Dim i As Long: i = 2 With Sheet1 p.Id = .Cells(i, 1).Value p.FirstName = .Cells(i, 2).Value p.Gender = .Cells(i, 3).Value p.Birthday = .Cells(i, 4).Value End With p.Id = "Hoge" Stop 'p.Greet End Sub
これからやりたいこと:複数行のデータをクラスで扱いたい
さて、これで1行分のデータに関してはクラスで扱えるようになりました。
ですが、エクセル表には、Bob以外のPersonもいらっしゃるわけで、それらをクラスとして扱おうと思ったら、以下のように人数分のインスタンスを用意しなければいけない…となると、ちょっとだるいです。
- エクセル表のデータ行の分だけ以下繰り返す
- Personクラスのインスタンスを生成する
- インスタンスにエクセル表からデータを取り込む
標準モジュールに、ループ処理を作ってもいいのですが、これ…どうせ必要ならクラスの機能として持っておいたほうがスッキリしますよね。
それで、今回は2の「インスタンスにエクセル表からデータを取り込む」という処理をクラスモジュールPersonの処理として寄せてしまいたいと思います。
インスタンスの初期データをセットするメソッド
VBAにはコンストラクタがない
実は、他の言語でいうと、インスタンスの生成とデータの初期化がいっぺんに行える言語が多くあります。
一般的にコンストラクタと呼ばれる関数です。
コンストラクタを作成しておくと、インスタンスを生成したときに自動的に呼び出されて、必要なデータをセットできるのです。
残念ながらVBAにはコンストラクタのような機能は存在していません…。
ただ、どうせインスタンスを生成してから初期データをセットするのであれば、それを楽に行えるメソッドは作っておいて損はないですよね。
インスタンスの初期化をするメソッド
今回、データはエクセル表に展開されています。
ですから、その1行分のデータ範囲つまりRangeオブジェクトを渡したら、それをプロパティにセットしてくれるようにしてくれればシンプルに作れそうです。
クラスモジュールPersonに、以下のようなSubプロシージャInitializeを追加して、Initializeメソッドを作ります。
Public Sub Initialize(ByVal rng As Range) id_ = rng(1).Value FirstName = rng(2).Value Gender = rng(3).Value Birthday = rng(4).Value End Sub
1行分のセル範囲をRangeオブジェクトで受け取って、左上のセルの値から順に、id_、FirstName、Gender、Birthdayにセットをします。
エクセル表の列順さえ入れ替わることがなければ、これでいけそうです。
Initializeメソッドの動作確認
では、標準モジュールModule1を以下のように変更して、その動作を確認してみましょう。
Sub MySub() Dim i As Long: i = 2 Dim p As Person: Set p = New Person With Sheet1 p.Initialize .Range(.Cells(i, 1), .Cells(i, 4)) End With Stop 'p.Greet End Sub
Stopステートメントで中断しているときに、ローカルウィンドウを確認してみると、以下のようにすべてのプロパティが正しくセットされていることが確認できます。
まとめ
以上、エクセルVBAでクラスのインスタンス生成時にデータを簡単に格納するメソッドを作る方法をお伝えしました。
VBAにはインスタンス生成時にデータを初期化するコンストラクタがないので、その代わりになるメソッドを独自で作成する必要があります。
さて、次回はエクセル表の他のデータも取り扱えるようにコレクションを活用していきます。
どうぞお楽しみに!