Excel-VBAでクラスを使って機能を拡張する

どの言語にも定番のコードというのがあります。Excel-VBAでは
Application.ScreenUpdating = False
などは、皆さん何回も書いていると思います。

はたらきたくないという思いに関しては誰にも負ける気がしない私は、この何回も同じことを書くという行為が嫌で何とかできないかと試行錯誤してきました。対処法として「コードをメモ帳などにストックしておいて、そこからコピペする」や「IMEに単語登録しておいて変換で呼び出す」など、いろいろやり方はありますが、私がたどり着いたひとつの答えがクラスを使って機能を定義しておくという方法です。

手始めに(個人的には)最も使用頻度が多い「ThisWorkbook」をクラスを使っていろいろやります。

クラスモジュールでThisWorkbookを改造する

ThisWorkbookはApplicationオブジェクトが持つプロパティです。現在マクロが実行されているブックをあらわします。

  • ThisWorkbook.Save でブックが保存されます。
  • ThisWorkbook.Path でブックまでのパスが文字列で取得できます。

このように「今作業しているブック」を示すThisWorkbookは非常に使い勝手がよく、それだけ登場する機会も増えます。


話はそれますが「今作業しているブック」を ActiveWorkbookで「今作業しているシート」をActiveSheetで参照しましょうみたいに説明されていたり、サンプルコードでさらっと使われていたりすることがありますが、このやり方はオススメしません。

あえてユーザーが選択しているブック、シートに対して処理をするからこうしているんだよ、とわかって使っている場合意外はActiveなんちゃらでオブジェクトを指定するのは危険です。

理由をわかりやすく解説しているサイトを以前見たのですがブックマークし忘れました。要は「ユーザーの操作によってその時々で対象が変わる」というのがActiveなんちゃらですよ、つまり、VBAのあずかり知らぬところで操作対象が変更される可能性がある、ということを知っておきましょう。かくいう私もこれで何回も無関係なシートにデータを書き込んでしまったことがあります。

さて、ThisWorkbookですが、オブジェクトブラウザーで確認すると次のようになっています。

正体はWorkbookオブジェクトだというのがわかります。Applicationオブジェクトが現在作業中のブックのWorkbookオブジェクトをこのプロパティへ格納しているということでしょう。先のSaveメソッドもPathプロパティもWorkbookオブジェクトが持っているそれです。

オブジェクトの詳細がわかったところで、クラスモジュールを使って、このThisWorkbookに追加の機能を持たせていきます。

どうやるかというと、いわゆるラッパークラスを作ります。お約束なので言っておきますが、チェケラッチョの方のラッパーではありません。ラッパーはWrapperで包み込むという意味です。ThisWorkbookがクラスに包まれているイメージです。

このクラスにメソッドとして Application.ScreenUpdating = False など汎用的に使う機能を全部突っ込んでしまいます。こうすることで、クラスのメソッドを呼ぶだけで、必要な処理を一度に実行できます。

もう一つラッパークラスの利点があります。ていうか、こちらの方がラッパーにした主たる理由です。

ThisWorkbookを使うということは、作業中のブック自体へ何かしら操作をしたいということに他なりません。よって、重要になってくるのが、ファイルパス、ファイル名といった情報です。これらは標準で備わっているプロパティから取得できるのですが、不満点があります。それがプロパティ名がわかりにくいことです。

次はブックの絶対パスを示すプロパティです。
ThisWorkbook.FullName

えっ?Pathじゃないのって思いません?私は思いました。

現に「Pathってカレントフォルダーのパスまでしか取れないのかよ、めんどくせーなー」と思いながら
ThisWorkbook.Path & “\” & ThisWorkbook.Name
とつなげて絶対パスを作ってました。FullNameの存在は最近知りました。

このように自分が思っている名前とかけ離れたプロパティ名で望みのパラメータが提供されていることがあります。当然、覚えられません。だったら自分の思っている名前に変更してしまえば良いのです。ラッパークラスを使うことでこれが可能です。

こうして必要な機能、条件をリストアップしたら、僕の考えたThisWorkbookあらため
ThisWorkbookExクラスとして定義します。

Private Base_ As Workbook
Private IsSilent_ As Boolean

Property Get FullPath() As String
    FullPath = Base.FullName
End Property

Property Get FileName() As String
    FileName = Base.Name
End Property

Property Get FileNameNoExtension() As String
    FileNameNoExtension = Left(Base.Name, InStrRev(Base.Name, ".") - 1)
End Property

Property Get FileExtension() As String
    FileExtension = Right(Base.Name, InStrRev(Base.Name, ".") - 1)
End Property

Property Get CurrentDirPath() As String
    CurrentDirPath = Base.Path
End Property

Property Get IsSilent() As Boolean
    IsSilent = IsSilent_
End Property

Property Get Base() As Workbook
    Set Base = Base_
End Property

Sub Silent()
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
    Application.Calculation = xlCalculationManual
    IsSilent_ = True
End Sub

Sub UnSilent()
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    Application.Calculation = xlCalculationAutomatic
    IsSilent_ = False
End Sub

Sub Save()
    Base.Save
End Sub

Private Sub Class_Initialize()
    Set Base_ = ThisWorkbook
End Sub

Private Sub Class_Terminate()
    If IsSilent_ Then
        Call UnSilent
    End If
End Sub

次のように使います。

Sub test()
    Dim ThisWorkbookEx As ThisWorkbookEx
    Set ThisWorkbookEx = New ThisWorkbookEx
    
    Debug.Print ThisWorkbookEx.FileName
    Debug.Print ThisWorkbookEx.FileNameNoExtension
    Debug.Print ThisWorkbookEx.FileExtension
    Debug.Print ThisWorkbookEx.FullPath
    Debug.Print ThisWorkbookEx.CurrentDirPath
    Debug.Print ThisWorkbookEx.Base.path
End Sub

C:\expy\test.xlsm にファイルが存在している環境での実行結果は次の通りです。※環境により¥マークがバックスラッシュになります。

test.xlsm
test
xlsm
C:\expy\test.xlsm
C:\expy
C:\expy

解説

ThisWorkbookExクラスはThisWorkbookを内包しています。
コンストラクタ(Class_Initialize)でThisWorkbookを自身のプロパティとして格納します。

Private Sub Class_Initialize()
    Set Base_ = ThisWorkbook
End Sub

これによりThisWorkbookEx.BaseプロパティからThisWorkbookが持つすべての機能を利用できます。

ThisWorkbookEx.Base.Path

このコードは以下と同義です。

ThisWorkbook.Path

BaseプロパティからThisWorkbookのプロパティをgetter(Property Get) を経由して返すことで好きな名前でパラメーターを取得したり、加工した後で取得したりできるようにしています。

プロパティは次の通りです。

名称説明
FullPathString絶対パス
FileNameStringファイル名
FileNameNoExtensionString拡張子なしファイル名
FileExtensionString拡張子
CurrentDirPathStringカレントフォルダーのパス
IsSilentBooleanサイレントモードのフラグ
BaseWorkbookThisWorkbookへの参照

メソッドとして

  • 画面更新の停止
  • 再計算の停止
  • 確認ダイアログの抑止

のVBA実行前の3点セットを全部設定するSilentを実装しています。Silentメソッドによって各種抑止が有効になっているかどうかをIsSilentプロパティとして保持します。

Sub Silent()
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
    Application.Calculation = xlCalculationManual
    IsSilent_ = True
End Sub

Sub UnSilent()
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    Application.Calculation = xlCalculationAutomatic
    IsSilent_ = False
End Sub

Private Sub Class_Terminate()
    If IsSilent_ Then
        Call UnSilent
    End If
End Sub

SilentメソッドでFalseへ変更されたApplicationのプロパティはThisWorkbookExクラスのインスタンスが破棄されるときにデストラクタ(Class_Terminate)によってTrueに戻されます。よって通常はプロシージャを抜けるとTrueが設定されます。またUnSilentメソッドにより明示的にTrueを設定することもできます。

Sub test1()
    Dim wbex As ThisWorkbookEx
    Set wbex = New ThisWorkbookEx
    
    wbex.Silent
    wbex.Base.Worksheets(1).Delete
End Sub

Sub test2()
    ThisWorkbook.Worksheets(1).Delete
End Sub

このコードでは、test1プロシージャでは警告なくシートが削除されます。続けて実行したtest2プロシージャでは削除前に警告ダイアログが表示されます。

Saveメソッドはそのまま、BaseのSaveメソッドをコールしているだけです。ブックの上書き保存が実行されます。よく使うので入れときました。

使用方法

1.このページ下部のボタンでzipファイルをダウンロードして展開します。クラスファイルが入っています。

2.VBEにクラスファイルをドラッグ&ドロップします。

クラスモジュールにThisWorkbookExクラスが追加されます。

3.プロシージャでクラスをインスタンス化してご利用ください。

ダウンロード

利用上のご注意

  • ダウンロードしたファイルを利用したことにより生じた結果については、利用者ご自身に責任を負っていただきます。
  • ご利用前に使用方法をご確認ください。
  • 当方は成果物の正確性について最善を尽くしますが保証はいたしません。
  • Windows11 Microsoft365 環境でのみ動作確認済み。

Downloadボタンを押下した時点で注意事項に同意したものとみなします。

ThisWorkbookEx.zip

プロパティ名の変更や、メソッドを追加して自分の使いやすいようにどんどん改造しましょう。ただしあまり具象的な処理を入れないようにしてください。具象化すればするほど、そのファイルでは便利になりますが他のファイルへ使えなくなります。

おわり。