VBAで扱える代表的なExcelのオブジェクトにWorkbook、Worksheet、Rangeなどがある。
- ひとつのブックにはひとつのWorkbookオブジェクトが対応している。
- ひとつのシートにはひとつのWorksheetオブジェクトが対応している。
ではひとつのセルに対応する固有のオブジェクトは?
5秒、4、3、2、1、はい。
Cellと答えたあなた。ぶっぶー。
Rangeと答えたあなた。ぶっぶっぶー。
実はひとつのセルに対応する固有のオブジェクトは存在しないってのが答え。
「固有の」ってとこがミソ。
まずCellというオブジェクトは存在せず、WorksheetオブジェクトのCellsプロパティが返すのは全セルを表すRangeオブジェクトである。このことは以下の記事で詳しく書いた。
thom.hateblo.jp
そもそもセルがいくつあるか考えてみよう。Excel2007以降、扱えるセル範囲は16,384桁1,048,576行となっている。つまり単純に掛け算して約170億個のセルが存在することになる。これらにそれぞれ対応するオブジェクトが存在するとしたらExcelだけでPCのメモリを食いつぶしてしまう。
じゃあいったいRangeとは何なのか。
Rangeとはシートを操作するエージェント(代理人)のようなものである。
ひとつ実験をしてみよう。
オブジェクトが一致するかどうかを比較する方法として、Is演算がある。
もしSheets(1).Range("A1")がひとつの固有なRangeオブジェクトを返すなら、以下はTrueになるはずだ。
Sub hoge() MsgBox Sheets(1).Range("A1") Is Sheets(1).Range("A1") End Sub
実際に実行してみるとわかるが、上記のマクロはFalseになる。
同じセルを指してるのになんで!?と思うかもしれないけれど、これがエージェントと表現した所以。
つまりRangeとはWorksheetに代わってセルを操作する代理人(エージェント)である。
こんな風に、同じA1セルを管理していても、同じエージェントであるとは限らない。
だからこうやってIsで比較すると。
違うんだ!と。
つまりWorksheetオブジェクトのRangeプロパティは評価するたびに新しいRangeオブジェクトを生成しているのだ。
ちなみに変数に入れてあげれば当然一致する。
Sub hoge() Dim r As Range Set r = Sheets(1).Range("A1") MsgBox r Is r End Sub
これはTrue。
ここで面白いのが、以下のようにOffsetをかますと不一致になるという点。
Sub hoge() Dim r As Range Set r = Sheets(1).Range("A1") MsgBox r Is r.Offset(0, 0) End Sub
Offset(0, 0)ということは実質的におなじセルを指してるのに不一致。
つまりOffsetは内部で新しいRangeエージェントを作って返してるようだ。
以前クラスモジュール内で自身と同じ型の別インスタンスを返すという処理をやったけど、まさにあれと同じ。
thom.hateblo.jp
Offsetプロパティは内部でRangeをNewして返してるイメージ。実際に中身見たわけではないので具体的な実装は知らないけど。
なお、同じセルを指しているかどうかを調べたかったらAddressプロパティをイコールで比較してあげればよい。
Sub hoge() Dim r As Range Set r = Sheets(1).Range("A1") MsgBox r.Address = r.Offset(0, 0).Address End Sub
これはTrueになる。
ちなみにシートの場合はどうかというと、
Sub hoge() MsgBox Sheets(1) Is Sheets(1) End Sub
このように普通にIsで比較してもTrueが返される。
以下のように表現を変えてみても同じくTrue。
Sub hoge() MsgBox Sheets(1) Is Sheets("Sheet1") End Sub
以下のように一旦別シート指してから戻しても同じようにTrueを返す。
Sub hoge() Dim sh As Worksheet MsgBox Sheets(1) Is Sheets(1).Next.Previous End Sub
つまりこれが固有オブジェクトであるということ。
ひとつのセルに対応する固有のオブジェクトが存在しないという意味が伝わっただろうか。