Rangeオブジェクトと、Rangeプロパティの違いを解説します。
同じところ
どちらも「セル」または「セル範囲」を扱います。
違うところ
一言で言ってしまえば、「Rangeオブジェクトを取得する、たくさんあるプロパティの中のひとつがRangeプロパティ」です。
もっと詳しく
↑の説明でわかる人はあまりこのページに来ないと思いますので、
詳しく説明していきます。
知ったからと言ってすぐに実務に活きるような話ではないので、
分からない部分は読み飛ばしながら、気楽に読んでください。
結構難しい話なので、見通しが立てやすいように先に最終目標から。
Range("A1").Value = 1
- これってRangeオブジェクトですか?
- それともRangeプロパティですか?
というのを説明するために、順を追って説明していきますね。
オブジェクト.プロパティ
まずはオブジェクトとプロパティが何なのかを簡単に。
このコードを見てください。
Worksheets(1).Name = "集計表"
何の変哲もない、シート名を変更するコードです。
このコード中の「.」に注目してください。
「.」は「の」と読むと理解しやすいです。
実際に↑の例でも、「第1シートの名前」と訳すことができます。
この「.」がプログラミングの世界ではかなり重要で、
「誰」の「何」を扱うかを指定する際、
誰.何 = "集計表"
という風に書けるように、すべての機能が整備されています。
プログラミングの世界では、この「誰」をオブジェクト、「何」をプロパティと呼びます。
例えば↑の例
Worksheets(1).Name = "集計表"
を、きっちりした用語で書くと、
「Worksheetオブジェクト」である第1シートの、
「Nameプロパティ」に"集計表"を代入した。
と表現します。
ここまではOKですかね?
プログラミングをやる上では、この「オブジェクト」と「プロパティ」は重要なので、この機会に覚えてしまってください。
別に難しく考えなくていいです。
「誰の何」を、
オブジェクト.プロパティ
と書けるように、多くのプログラミング言語は作られていますよ。
というだけの話です。
セルを表すオブジェクト = Rangeオブジェクト
ここで本題のRangeに移りましょう。
Range("A1").Value = 1
このコードを↑の通り解釈すれば、
「Range("A1")」がオブジェクトで、「Value」がプロパティですね。
さて、さっきの「ワークシート」は「Worksheetオブジェクト」という名前のオブジェクトでしたよね。
じゃあ「セル」ってなんていう名前のオブジェクトなんでしょう?
この答えがまさに「Rangeオブジェクト」です。
まずここが紛らわしいポイントの第1弾なのですが、
「Cellオブジェクト」が集まって、「Cellsコレクション」ではないのです。
「Cellオブジェクト」が集まって、「Rangeオブジェクト」でもないのです。
1個のセルでも、長方形のセル範囲でも、飛び飛びのセルをカンマでつないだ複数セルでも、どれも「Rangeオブジェクト」なのです。
「Rangeオブジェクト」が集まったものも、「Rangeオブジェクト」なわけです。
「Rangeオブジェクト」の中には、たくさんの「Rangeオブジェクト」がいます。
ということで、ひとまず「セルやセル範囲ならなんでもRangeオブジェクト」です。
Cells(1, 1)
もRangeオブジェクトですし、
Range("A1") Range("A1:C3")
も、もちろんRangeオブジェクトです。
これでひとつ謎が解けましたね。
Rangeオブジェクトを取得するプロパティたち
じゃあもう一つの謎、「Rangeプロパティ」って何なのでしょう?
正確ではない、ちょっと乱暴な説明になりますが、
Range("A1")
このコードの中で使った、
Range( )
この関数っぽいものがRangeプロパティです。
Rangeプロパティの引数に、"A1"を渡して取得したA1セルが、Rangeオブジェクトと言うことです。
ここがめっちゃ紛らわしいんですよ。
名前が一緒だから最初はすごい混乱するんです。
これは↓の例を見ると、ちょっと整理できるかもしれません。
- パスタを料理する
- 料理を運ぶ
- お母さんに電話する
- お母さんの電話を買う
などと同じだと思ってください。
「名詞」と「動詞」に同じ単語が使われるのは珍しくないですよね?
それと一緒のことです。
料理(Rangeオブジェクト)を作ることを、
料理する(Rangeプロパティ)というわけです。
セルを扱うオブジェクトはRangeオブジェクトしかありませんが、
そのRangeオブジェクトを取得するプロパティは、↓の通りたくさんあります。
Cells(1, 1) Rows(1) Columns(1) Cells(1, 1).Risize(2, 2)
これらはみんな、Rangeオブジェクトを取得するプロパティたちです。
これも料理に例えると、「煮る」「焼く」「切る」みたいに、
「料理」を作る方法がたくさんあるような感じです。
そしてその中でもRangeプロパティは万能で、
↑のプロパティを全部自分でやってしまいます。
Range("A1") Range("1:1") Range("A:A") Range("A1:B2")
これだけ万能だと仕方がないですね。
「煮る」「焼く」「切る」全部自分でやれるんですから、
紛らわしいですが「料理する」という、名詞そのものを名乗ることを許してあげましょう。
とこんな感じです。
最初の説明に書いた、
「Rangeオブジェクトを取得する、たくさんプロパティの内の、
もっとも万能なやつがRangeプロパティ」
が、なんとなくでも伝わったでしょうか?
※ 「一番万能だったからRangeを名乗るのを許された」は私の妄想というか例えです。
実際にMicrosoftさんがどう思ってRangeを名付けたのかなんて、もちろん私にはわかりません。
プロパティって右側なんじゃないの?
さて、これでRangeオブジェクトとRangeプロパティの説明はできたわけですが、
まだ一つ謎が残っています。
なぜこれをRange「プロパティ」と呼ぶのでしょうか。
一番最初の説明に戻りますと、
オブジェクト.プロパティ
これで「誰」の「何」でしたよね?
RangeプロパティもCellsプロパティも、
「プロパティ」というからには「何」にあたるわけです。
でも、
Range("A1").Value = 1
を見ると、Rangeはプロパティなのに左側にあります。
なぜでしょう?
答えは単純で、「ActiveSheet.」が省略されているからです。
Rangeプロパティは、より正確には
「WorksheetオブジェクトのRangeプロパティ」
ということです。
これが紛らわしいポイント最終章ですね。
オブジェクト.プロパティと、事は単純な話ではないのです。
「オブジェクトA.○○○○○B.プロパティC」とつながっているときは、
- BはAにとってはプロパティ
- BはCにとってはオブジェクト
というわけなんですよ。
これは家族に例えるとわかりやすいのですが、
オブジェクトとプロパティは、親子と表現されることもあります。
というか実際に、Parent(親)を使うと、
Range("A1").Parent
で親オブジェクトであるワークシートを取得できます。
それで、オブジェクトをプロパティのお父さんだとするじゃないですか。
でもお父さんだって、おじいちゃんから見れば息子ですよね?
それとおんなじ話です。
Valueのお父さんであるA1セルも、Worksheetの息子ですからね。
Worksheetおじいちゃんだって、Workbookひいおじいちゃんの息子です。
最終的には、家系図をたどったご先祖様である、Excel藩のApplicationオブジェクト大名から続く由緒正しいお家柄なわけです。
今回の話では、
Worksheetオブジェクトの子であるRangeオブジェクトの、
さらにその子であるValueプロパティに値を代入していたということです。
その上で、Worksheetオブジェクトの子であるRangeオブジェクトを取得するために、
Rangeプロパティを使っているということですね。
これですべての謎は解けたでしょうか?
まとめ
- セルやセル範囲を扱うオブジェクトを「Rangeオブジェクト」と呼ぶ
- Rangeオブジェクトを取得するためのプロパティが、親であるWorksheetオブジェクト内にたくさん用意されている
- その中で一番万能なのが、オブジェクトと同じ名前のRangeプロパティ
というお話でした。
Rangeはすごく難しいオブジェクトですが、
逆にこれさえわかれば、VBAのオブジェクトはオールOKみたいなものです。
初読で完全に理解するのは難しいかもしれませんが、
まあ気長に付き合っていきましょう。
RangeはVBAの主役ですから、いやでも長い付き合いになりますよ(´∀`)
おまけ:ひとつ嘘をついてるので訂正します
さて、今回の話は難しすぎて、どうしても簡単にせざるを得ない部分で、ひとつ嘘をついています。
今までの話をすべて終えた今なら、なんとなくわかると思うので、一応訂正しておきますね。
一応というくらいなので、実務には全く関係ない、厳密な用語の定義の話です。適当に読み流してください。
単刀直入にどこが嘘だったかというと、
Range("A1")
これがRangeオブジェクトだと言いましたが、
厳密にはこれは「引数に"A1"を渡されたRangeプロパティ」で、
「このプロパティによって取得されるオブジェクトがRangeオブジェクト」です。
実際にコードが実行され、ActiveSheetがどのシートかわかるまでは、
どのオブジェクトを指すのかすら決まっていませんし、もしからしたらできないかもしれません。
これと同じ話で、あたかも「プロパティ」という実物があるかのように「家族の話」をしましたが、実際に家族をなしているのは「オブジェクト」です。
「オブジェクトとプロパティが親子」なのではなく、
「親オブジェクトと子オブジェクトが親子」です。
この親子の間で「子オブジェクトを取ってくるための方法≒関数」が、プロパティということです。
オブジェクトに限らず、値を扱うNameプロパティにしても、Nameプロパティという実際の値があるのではなく、
「シートの名前を格納している実際の値にアクセスするための関数」
と表現した方が正しいです。
話をまとめると、コード上に、
Workbooks("テスト.xlsx").Worksheets("集計表").Range("A1").Value
こう書いてあるとします。
この式中にオブジェクトは無く、すべてプロパティです。
もちろんExcelさんの内部では「オブジェクト-オブジェクト-オブジェクト-値」が実際に紐づいているのですが、
このコード自体は、
「オブジェクトを返すプロパティ.オブジェクトを返すプロパティ.オブジェクトを返すプロパティ.値を返すプロパティ」
です。
コードの段階では全部プロパティで、実行して初めてオブジェクトになる
という解釈がわかりやすいでしょうか。
オブジェクト-プロパティの関係をわかりやすくするために、
「オブジェクトA.○○○○○B.プロパティC」とつながっているときは、
- BはAにとってはプロパティ
- BはCにとってはオブジェクト
とも書いていましたが、Bは生まれも育ちもオブジェクトであり、
そのBを取得するプロパティがAに用意されているというのが厳密な説明です。
と、まあ一応訂正はしましたが、普通に話をしている上では、
Range("A1")
これはもうオブジェクトでいいと思いますよ。
これをオブジェクトを返すプロパティって言う必要があるかというと…
この話は、厳密な用語の定義の話です。
原子は物質の最小単位とか言っておきながら、電子とか陽子とか出てきて、最後はリプトンだかレプトンだか紅茶が出てくるみたいな話に近いと思います。
ということで、嘘を訂正するといっておきながらやっぱり嘘で締めますが、
- Range("A1") … オブジェクト
- Range( ) … プロパティ
で、実務上はOKだと思います。
この違いを認識できることは、ちゃんと実務に役立ちます。
これ以上先の話は、学者様の領域と思っておいても、
別に困ることはないと思いますよ(´∀`)
おまけ:本題と関係ない嘘
本題と関係ないので、書くか迷ったのですが、
この話を最後まで読んでくださった方のために書いておきます。
親を省略したRangeプロパティの親オブジェクトは、
実はActiveSheetではありません。
例えば、
Worksheets("Sheet2").Range("A1") Range("Sheet2!A1")
これはどっちも「Sheet2」のA1セルを取得します。
Rangeプロパティを省略した場合は、親はApplicationオブジェクトです。
その上で、Applicationさんが、省略時の親シートを補完してくれる感じです。
引数で渡すStringやObjectで指定があるときは、その指定シートからRangeオブジェクトを取得します。
それが無いときは、ActiveSheet(シートモジュールならそのシート)を補完します。
なんて万能なやつなんだ。
ということで、この話は忘れてください(笑)
良く対比されるCellsプロパティの親オブジェクトを省略した場合は、
ちゃんとActiveSheetで、Wroksheetsオブジェクトです↓
Cells(1, 1) ' これは掛け値なしにActiveSheetを親とするプロパティ
これと一緒と思っていても、何ら問題は発生しませんし、
これと一緒だと思って使い分けた方が、間違いなくわかりやすいです。
忘れてしまった方がいいような気がします(笑)