【Excel】VBAの階層構造について- 入れ子構造になっているのをご存じですか

  • [記事公開]2022.06.20[最終更新]2023.02.21
  • Excel

Yahoo!知恵袋で、With Application With .ActiveSheetと記述している質問者がいて、ActiveSheetの前のドットはいらないと回答者につっこまれていました。

With Application
.ScreenUpdating = False
With .ActiveSheet
For i = .Range(conStrR) To .Range(conEndR) Step conStep
.Range(conCell).Value = i
.Application.ActivePrinter = "DocuWorks Printer on Ne03:"
ActiveSheet.PrintOut
Next
End With
.ScreenUpdating = True
End With

指摘の個所は3行目ですね。確かに冗長だなとは感じるけど、階層構造を意識しているコードであるなら、別にありなんじゃ・・・と個人的には思いました。

でもさすがに、6行目の.Application.ActivePrinterの、Applicationの前のドットは不要だなと思いました。これって、

Application.ActiveSheet.Application.ActivePrinter

っていう意味ですよね?

こういうコードを書く人は、あまりオブジェクトブラウザーを使わないのかなあと思いました。

VBAのオブジェクトブラウザーの使い方を少しだけ紹介します。

VBAのオブジェクトブラウザー

ExcelでAlt+F11を押すと、VBE(VisualVasicforApplicationエディター)が開きます。

VBE

このVBEでF2を押すと、オブジェクトブラウザーというのが開きます。

オブジェクトブラウザー

デフォルトではすべてのライブラリが表示されるようになっていますが、これを現在利用可能なライブラリを選択して表示することもできます。

すべてのライブラリではなく、利用可能なライブラリを絞って表示することもできる。

私の環境だと、ExcelとVBAとVBAProjectの3つのライブラリが表示されました。試しにExcelを選んでみます。

Excelライブラリが表示されたところ。

「クラス」というところの一番上に表示されている<グローバル>を選択した状態だと、右側のペインに’<グローバル>’のメンバーが表示されます。

  • ActiveCell
  • ActiveChart
  • ActivePrinter
  • ActiveSheet
  • ActiveWindow
  • ActiveWorkbook
  • AddIns
  • Application

などと、おなじみのActiveなモノが並んでいます。

同様に、クラスに表示されているリストを選択すると、そのクラスが持つメンバが確認できます。

オブジェクトブラウザーというのは、今使えるオブジェクトが何なのか、どうやって使うのかを簡単に調べるために使います。

VBAの階層構造もこのオブジェクトブラウザーを見れば分かります。

VBAの階層構造

VBAは階層構造になっています。

一番上がExcelです。

コードで書くと、

Excel.Application.ScreenUpdating = true

なんて風になります。

Excel.の部分は省略して記述することが多いです。

Application.ScreenUpdating = true

Excel.Applicationの下に、たくさんのコレクションやクラス(オブジェクト)やプロパティが用意されています。

例えば、ブック。

Debug.Print Excel.Application.ThisWorkbook.Name

このコードの意味は、ブックの名前をデバッグで吐き出してねという意味です。でも普通、こんな風には書きません。次のように書くことの方が多いです。

Debug.Print ThisWorkbook.Name

(この場合、Excel.Applicationが省略されたというより、VBAProjectライブラリのThisworkbookが指定されたと見るべきなんでしょうが、別のライブラリの話をし出すと脱線になるので、ここではやめておきます)

ワークシートも、本来の(?)書き方ですと、次のようになります。

Excel.Application.Workbooks(1).Worksheets.Item(1).Select

先頭ワークシートを選択しなさいという意味のコードです。

Worksheets(1).Select

こんな風に、省略した書き方もできます。

この場合、どのブックのワークシートかというと、アクティブなブックのワークシートとみなされます。

アクティブなブックが存在しないときは、実行時エラーとなります。

アクティブなブックが存在しないときなんてあるの!?と思うかもしれませんが、アドインだとけっこうあります。ですから、なるべく親のクラスは書いてあげた方が無難です。あいまいさの回避にもなります。

それからRange。

Thisworkbook.Worksheets(1).Range("A1").Select

これは、

Range("A1").Select

と省略することもできます。

できますが、省略した場合、アクティブなブックのアクティブなシートと解釈されてしまいますので、もしもアクティブなブック、アクティブなシートが存在しないなら実行時エラーとなります。

こんな風に、ExcelのVBAは階層構造になっているのですが、多くの場面で省略が可能です。マクロの自動記録でもRangeはWorksheets(1).Range(“A1”)ではなく、いきなりRange(“A1”)と記録されます。このせいか、初学者にだいぶ混乱を招いているようです。

Application.ActiveSheet.Application.ActivePrinterの意味

冒頭に紹介したApplication.ActiveSheet.Application.ActivePrinterについて、階層構造を意識した?コード??なのかな???と一瞬思いましたが、全然そんなことはなく、単なるどこかのコードのコピペなんでしょうね・・・。

まず、Application.ActiveSheetの部分は、意味がないですね。メリットがありません。ActiveSheetはExcel.Applicationの中の一つのメンバーだってことは分かり切っていますから、どのブックかを指定するならともかく、親がExcelですってことをあらためて表明したところで、何の得もありません。

だから、ここはActiveSheetだけでよいと思います。

でもその前に、.Application.ActivePrinterの部分に注目すると、ActivePrinterもExcel.Applicationのグローバルなメンバですから、Application部分があってもなくても、意味がないです。単独で使えます。

例えば、ExcelだけでなくWordやPowerPointも同時に使っているようなコードであるならば意味があるのですが、そうでないならば、Application部分はいらないでしょう。

だから結局、ActiveSheet.Application.の部分もいらないってことになり、ActivePrinterだけでよいということになります。

ついでにいうと、その次の行で、ActiveSheet.PrintOutとしています。

PrintOutにはオプションでActivePrinterを指定できますので、

オブジェクトブラウザーで見たPrintOut。引数の中にActivePrinterがあるのが分かる。

次のように記述すれば、Application.ActiveSheet.Application.ActivePrinterの行は全部いらないってことになります。

ActiveSheet.PrintOut ActivePrinter:="DocuWorks Printer on Ne03:"

VBAの階層構造を意識する必要性って?

巷にはびこるVBAのコードは、階層構造なんて意識せず、いきなり省略した形で書いてあるものが多いので、最初はそういう言語なのかな??と勘違いします。私もずっと階層構造であることを意識せずにいました。

実際問題、階層構造を意識しなくても困らないことも多いです。

階層構造を意識しないといけないのは、アドイン化したときです。通常マクロブック(.xlsm)で作業していれば足りるのですが、何かの必要に迫られてアドイン化(.xlam)したときに、すべてのActiveなCell、ActiveなSheet、ActiveなWorkbook、それからThisworkbookに対して見直しが迫られます。どう見直すかというと、省略化していた階層構造を、省略しない形になおすのです。

また、ユーザフォームを使うときも否応なく階層構造を意識することになります。