1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VBAに出てくるクラスとして扱われるものについて

Posted at

#主な話

  1. VBAでクラスに分類されるもの
  2. PredeclaredIdって何してるの
  3. ThisWorkbookとSheet

経験則で書いてるので間違っていることあれば指摘お願いします。

##VBAでクラスに分類されるもの
最初の記事でちょろっと触れたが、ユーザーフォームはクラス。
他にもThisWorkbookやSheetもクラスだがこいつらはフォームより特殊でNewできなかったり、既定のインスタンスにNothingを設定できなかったりする。
エクスポートして中身をテキストエディタで見るそれぞれこうなる。

ThisWorkbook.cls
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "ThisWorkbook"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Option Explicit
Sheet1.cls
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "Sheet1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Option Explicit
UserForm1.frm
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} UserForm1 
   Caption         =   "UserForm1"
   ClientHeight    =   3015
   ClientLeft      =   120
   ClientTop       =   465
   ClientWidth     =   4560
   OleObjectBlob   =   "UserForm1.frx":0000
   StartUpPosition =   1  'オーナー フォームの中央
End
Attribute VB_Name = "UserForm1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

ユーザーフォームはVERSION 5.00となっていてCLASSと書いていないがNewできる。

どれもPredeclaredIdがTrueになっている。
これは普通のクラスを取り出して設定したことがある人もいると思うが、Trueにするとクラス名が既定のインスタンスとして設定され、Class1.Methodのような形でどこからでもメソッドを呼び出せるようになるというもの。
後述するがこれ目的なら別にファイルに取り出して書き換えて入れ直すなんて面倒なことはしなくてもいいというのが正直なところ。

なおclsファイルになってしまって戻せないThisWorkbookとSheetは別として、frmファイルのこれをFalseにしてもインポートすると勝手にTrueにされるので、既定のインスタンスのないフォームというものは作れない。

##Attribute VB_PredeclaredId = Trueは何をしているのか

'普通のクラスの使い方
Dim ClassDim As Class1
Set ClassDim = New Class1
Call ClassDim.Method
'PredeclaredId = Trueにしたクラスの使い方
Call Class1.Method

このようにインスタンスを作らないでもクラス名からメソッドを呼べるというのが特徴。
なのだが、実際のところやってるのは標準モジュールで以下のように宣言してるのと大差ない。

Module1.bas
Option Explicit
Public Class1 As New Class1

なぜかと言うとPredeclaredId = Trueに設定したクラスは最初に呼び出されたときにInitializeが働く。
つまり最初に参照されたときにNewされているので自動的にクラス名と同名の変数がAs Newで宣言されるような設定ということ。
厳密にはなにか違うのかもしれないが、わざわざ取り出して設定して入れ直して……というのが手間だと思うならこれも手だと思う。
結局Nothingと比較しても常にFalseになることや、意図しないタイミングでInitializeが走るという点では変わらないので……。

###ユーザーフォームで確認してみる

ユーザーフォームのテスト
Dim A As UserForm1
Dim B As UserForm1
Set A = UserForm1 '※
Set B = UserForm1
Debug.Print A Is B 'Trueと表示される
Set UserForm1 = Nothing
Set B = UserForm1 '※
Debug.Print A Is B 'Falseと表示される

最初にAとBにUserForm1をセットする。
このときは同じインスタンスを参照しているので当然比較すればTrueが返る。
次にUserForm1にNothingを設定してからBを設定し直している。
その後に比較するとBに設定されるのは新たなインスタンスとなり、結果はFalseとなる。
そしてUserForm1のInitializeにDebug.Printを仕込んでおくと※のタイミングで実行される。

Dim MyForm As UserForm1
Set MyForm = New UserForm1

他から参照されて変化されると困る場合はUserForm1を直接使わずにNewして使う方がいい。
広い範囲から同じ見た目のフォームを複数使う場合はPublicに役割別の変数をUserForm1型で宣言してそれぞれにNewして使えばいい。

##ThisWorkbookとSheet
この2つはExportすると普通のclsファイルになってしまうので入れ直すことができない。
Excelのシートなどに対応しているのだから当たり前といえばそう。

ThisWorkbookとSheetはVB_ExposedがTrueとなっている。
ThisWorkbookとSheetはNewできないのでこのExposedがTrueになるとNewできない?
また、これらについては「Set ThisWorkbook = Nothing」のようにNothingを設定することができない(クラスとフォームはできる)
ちなみにクラスでこれをTrueにしていてもインポートしてエクスポートするとFalseにされているので、自作クラスに設定することはできないようだ。

ちなみにThisWorkbookもオブジェクト名(=クラス名)を変えることができるが、変更してもThisWorkbookで同じものを参照できる。
例えばThisWorkbookのオブジェクト名をThisWorkbook2にした場合、ThisWorkbookと入力してCtrl+Jを押すとThisWorkbookとThisWorkbook2が並ぶ。
これは省略しない場合それぞれ、VBAProject.ThisWorkbook2とApplication.ThisWorkbookになると思うが、比較した場合Trueになるので名前や参照方法は違うが同じインスタンス。
ちなみにプロジェクト名を変えた場合は「VBAProject」の部分もそれに応じて変化する。

1
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?