はじめに
Visual Basicが独自のクラスを作成して使えるように、Officeに搭載されているVBAでも独自のクラスをプロジェクトに組み込むことができます。作成したクラスは、各Officeアプリケーションで「インポート」「エクスポート」ができるため、汎用性のあるクラスを1つ作成すれば他のアプリケーションのVBAでも利用できるようになります。
そこで、本稿ではExcel 2003で利用できるクラスを作成しながら、VBAでクラスを作る方法を紹介します。
対象読者
Excel VBAを使ってマクロ(プログラム)を作ったことのある人、Visual Basicが使える人が対象です。
必要な環境
Excel 2000、2002、2003が使用できる環境。
クラスは便利
VBAでクラスを作成するメリットは、複雑な処理を1つのオブジェクトにまとめ、プロパティやメソッドを通じてその機能を呼び出したりパラメータを設定することができる点です。そして、これらを汎用性のある形に仕上げておけば、他のプロジェクトに組み込んで使用できるようになります。
また、クラスにはプロパティやメソッドを組み込んで使うことができる点も大きなメリットです。汎用性のあるプロシージャを作成すれば、何もクラスを作成しなくてもコードをコピーすれば良いのですが、複雑なコードの場合、どこでどのプロシージャを使えばいいのか、書いた人しかコードの使い方が分からない、という問題点があります。しかし、クラスであれば、実装された各機能・設定をプロパティとメソッドで公開する形態を取りますから、その説明さえあれば誰でも組み込んで使用できるため、コードを使う側は分かりやすくなります。
また、作成したクラスは、単独のファイルにエクスポートしたり、それを別のファイルでインポートして使うことができるので、例えば汎用のクラスを作成してサーバに1つ置いておくだけで、複数のプロジェクトで使いまわすことができます。
クラスの作成手順
では、クラスをプロジェクトに組み込むにはどうすればいいのか、その手順を簡単に説明します。
- VBEditorを起動し、プロジェクトに「クラスモジュール」を挿入します。
- クラスのオブジェクト名を変更し、分かりやすい名前にします。
- クラスで使用するプロパティ・メソッドを作成します。
- 既にあるクラスを使用する場合は、プロジェクトの[ファイルのインポート]メニューで組み込むクラスをインポートします。
- プロジェクトに標準モジュールを追加し、クラスを使用するプロシージャを作成します。
Dim
ステートメントとNew
キーワードで、作成したクラスをオブジェクト化します。- 組み込んだプロパティに値を設定し、メソッドを実行します。
- 新規に作成したクラスは、プロジェクトの[ファイルのエクスポート]メニューで、単独のファイルにして保存すれば、他のプロジェクトでも利用できます。
単独のファイルに保存されたクラスは、テキストファイルで保存されていますので、テキストエディタで簡単にコードをコピー&ペーストできます。
Excel VBAでクラスを作る
では、Excel VBAで、簡単なExcel用のクラスを1つ作成してみましょう。このクラスは、共有化されているブックに、現在アクセスしているユーザー名とログイン日時を、ログ記録としてテキストファイルに落とす機能を実装しています。
ログファイルを保存するドライブ(フォルダ)のパスを設定する1つのプロパティと、ログファイル作成を実行する1つのメソッドを持ちます。
新しいクラスを作る
作り方はいたって簡単です。新しいブックを用意し、VBEditorを起動してください。プロジェクトに「クラスモジュール」を1つ追加します。
プロパティウィンドウで、このクラスのオブジェクト名をClass1
からAccessLog
に変更します。
クラスモジュールの宣言セクションに、Public
キーワードで文字列型変数PathName
を宣言します。これが、クラスのプロパティになります。変数名がそのままプロパティ名となり、設定する値は文字列型のデータ型になります。
Public PathName As String
簡単なプロパティをクラスに設定するには、この変数宣言を使います。
クラスにメソッドを作る
次に、CreateLog
という名前のプロシージャを1つ作成します。これが、このクラスのメソッドになります。引数を持たないSub
プロシージャで宣言します。
Sub CreateLog() End Sub
変数宣言
プロシージャ内に変数を5つ宣言します。
Dim UserInfo As Variant '------ 1 Dim UserCnt As Integer '------ 2 Dim Fname As String '------ 3 Dim LogMsg As String '------ 4 Dim DateName As String '------ 5
- ユーザー情報を格納
- アクセスしているユーザー数を格納
- ログを保存するファイル名を格納
- ログに書き込む文字列を格納
- 日付を文字列で格納する
ユーザー情報の取得
ブックにアクセスしているユーザー情報は、Application
オブジェクトのUserStatus
プロパティに格納されています。
このプロパティは、ユーザー1人に付き「ユーザー名」「アクセスした時点の日時」「アクセスモード」の3つの情報を配列で格納しています。1人につき3つの情報をアクセスしている人数分持ちますので、1から始まるn行3列の2次元配列となります。1次元にユーザーの人数、2次元にユーザー情報が格納されます。
このプロパティの値を取り出す場合は、受け取る変数のデータ型をバリアント型にしておきます。
UserInfo = ActiveWorkbook.UserStatus
これで、すべてのユーザー情報を受け取ることができます。ここでは、3人のユーザーがブックにアクセスしていますから、受け取った変数UserInfo
は3行3列の配列になります。
UserStatus
プロパティが返す配列は、添え字が「1」から始まる配列になります。 UBound
関数を使用すると、配列の最大要素数を取得できます。これを変数UserInfo
の1次元配列に対して使用すると、アクセスしているユーザー数を把握できます。
関数の戻り値は、変数UserCnt
に格納しておきます。
UserCnt = UBound(UserInfo, 1)
保存するログファイルの作成
次に、保存するログファイルには作成した日付をファイル名に付けるようにしたので、この日付の文字列を作成します。Date
関数を使うと、システムから現在の日付を取得できますが、Date
関数の戻り値が「2000/04/20」という書式で返ってきます。この書式だと記号「/」が含まれており、そのままではファイル名に使用できません。
そこで、Replace
関数で「/」記号を「-」に変換し、日付の文字列を「2000-04-20」に変換します。
DateName = Replace(Date, "/", "-")
クラスAccessLog
に設定したプロパティPathName
には、ログファイルを保存するファイルのドライブ・フォルダ名を設定します。そこで、これを使って、保存するファイル名をフルパスで作成します。ファイル名は、文字列AccessLog
と作成した日付、そして拡張子「.txt」を結合して作成します。
Fname = PathName & "\AccessLog" & DateName & ".txt"
例えば、2006年7月27日にログファイルを作成したとすると、このファイル名は「AccessLog2006-07-27.txt」というファイル名になります。プロパティPathName
に、「C:」というドライブ名を設定すれば、フルパスのファイル名は「c:\AccessLog2006-07-27.txt」となり、これが変数Fname
に格納されます。
FileSystemObjectの作成
Excelでテキストファイルを作成して保存するには、FileSystemObject
オブジェクトを使用します。このオブジェクトは、Excelが保有するオブジェクトではなく、VBAに組み込まれているオブジェクトで、コンピュータのファイルシステムへのアクセスを提供するオブジェクトです。
Excelのオブジェクトとは少し違う手順で使用します。まず、CreateObject
関数で、このオブジェクトのインスタンスを作成します。引数には、このオブジェクトのプログラムIDであるScripting.FileSystemObject
を記述します。そして、作成したオブジェクトへの参照をオブジェクト変数Fsobj
に格納します。
Set Fsobj = CreateObject("Scripting.FileSystemObject")
次に、FileSystemObject
オブジェクトが保有するメソッドCreateTextFile
を実行します。
Set txt = Fsobj.CreateTextFile(Fname, True)
このメソッドは、第1引数に指定したファイル名のテキストファイルを作成し、オープンします。第2引数には、既に同名のファイルがあった場合に上書きするかどうかを論理値で設定します。True
で上書きを許可します。
ファイルが無事作成できると、これをTextStream
というオブジェクトで返してきますので、Set
ステートメントでオブジェクト変数txt
に格納しておきます。
ファイル保存の実行
テキストファイルの準備ができたら、このファイルに書き込む文字列を作成します。これは、For
...Next
ステートメントで、ユーザー情報を格納している配列UserInfo
からひとりひとりのユーザー名とアクセス日時を取り出し、&
演算子で連結して1つの文字列にします。
For i = 1 To UserCnt LogMsg = LogMsg & UserInfo(i, 1) & ":" & UserInfo(i, 2) & Chr(13) Next
そして、TextStream
オブジェクトのWriteLine
メソッドを使って、作成したファイルに文字列を書き込みます。
txt.WriteLine LogMsg
最後に、作成したファイルを、TextStream
オブジェクトのClose
メソッドで閉じて完了です。
txt.Close
クラスを実装する
作成したクラスは、あくまでも定義をしただけで、雛形を作ったようなものです。このクラスを元に、実際に実行可能なオブジェクトを作成する必要があります。
プロジェクトに標準モジュールを1つ追加し、プロシージャ「ログの作成」を作ります。
Sub ログの作成() End Sub
プロシージャの冒頭で、Dim
ステートメントにNew
キーワードを付けて、クラスAccessLog
を実体化します。Dim
のあとにオブジェクト名MyLog
を記述し、As New
のあとに作成したクラスのオブジェクト名AccessLog
を記述します。
Dim Mylog As New AccessLog
これで、クラスAccessLog
を元に、新しいオブジェクトMylog
が生成されてメモリに読み込まれます。
オブジェクトを作成すると、クラスに実装されているプロパティとメソッドが利用可能になるため、まず、保存するログファイルのドライブ名を、プロパティPathName
に設定します。コードウィンドウに、「With Mylog」と記述し「.」を入力した時点で、プロパティPathName
とメソッドCreateLog
が選択候補に表示されます。
プロパティPathName
を選び、「=」のあとに「"c:"」と入力します。これで、ログファイルはCドライブに保存されます。
With Mylog .PathName = "c:"
パスを設定したら、メソッドCreateLog
を実行します。
.CreateLog End With
これで、このプロシージャ「ログの作成」を実行すれば、ブックにアクセスしている人のユーザー名とアクセス日時がテキストファイルに記録・保存されます。