★★★ Access2000VBA・Excel2000VBA独学~用語:ExcelVBA~「コレクション(=コレクションオブジェクト)」とは?~
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
※★ 自分で言ってりゃ世話無いですが・・・本当にすみませんが、本記事は(参考にはなると思いますが、でも)、「もしかしたらちょっといいかげんかもしれなかった」ですので、先に必ず以下のページをお読み下さい。
『 ★独学者が1年後にExcelVBAを爆発的に伸ばすための最低限の基礎知識メモ(ダイジェスト):★ (09)挫折しないための「コレクション」とは? 』
VBAプログラミングにおける「オブジェクト」とは、「目に見える・見えない・大きい・小さい」にかかわらず、「ユニット、パーツ、部品、機能の集合体、複合機能体」あるいは「ミニミニロボット」のことだと思って頂ければよいです。
文字列、数値、日付データ、論理値(True/Falseの2値など)、といった、「文字ベース」の一般データの「対義語」のようなニュアンスもあります。
一般データは文字通り、「文字ベース」なのですが、「オブジェクト」は、「ユニット、パーツ、部品、機能の集合体、複合機能体」あるいは「ミニミニロボット」という感じなので、「立体的・3D的」な「モノ」、「かたちあるもの」というイメージです。(ですので、文字ベースのデータには「機能」という概念はありません。しかし、オブジェクトには必ず「機能」があります。オブジェクトの中には「色んな機能が内包されています」。大分類的な言い方で言うと、プロパティ、メソッド、イベント、上下階層自由往来機能、上下階層機能流用機能、などです。)
そして「コレクション」も、その「オブジェクト」の「一種」です。
「コレクションオブジェクト」と呼んだりもします。
オブジェクトには大きく分けて「単一のオブジェクト」と、この「コレクションオブジェクト」の2種類があります。
「コレクションオブジェクト」は単一のオブジェクトたちを複数集めたものです。
また、別の言い方をすると、『 単一オブジェクトたちは「コレクションオブジェクト」に含まれています 』。
(=多くの単一オブジェクトたちは 何らかの「コレクションオブジェクト」に含まれています。ヘルプにも・・・、特に各単一オブジェクトのページに「単一オブジェクトたちはコレクションのメンバです」、みたいに書いてあります。)
そしてコレクションも、「機能の集合体」「複合機能体」です。
コレクションには各種の色んなものがありますが、また、それぞれが色んな「機能」を保持・内包していますが、でも、どれも基本的には、「単一のオブジェクトたちを管理したり、全て一括でゴソっと動かしたりする機能」を有しています。 コレクションは、そういう「ミニミニロボット」です。
なお、セルやシートといった各オブジェクトやその中に内包される機能(メソッドやプロパティ等)や、列挙(Enum)、定数などは、以下の図のように、ソフトウェアの画面上に見えてくるものもありますが、コレクションはどちらかというと(原則的には)、このように目に見えてくるオブジェクトではなく、「目に見えない、内部的なオブジェクト」だと考えていいと思います。
(「目に見えない、裏方で仕事する、内部的なミニミニロボット・・・」みたいな感じです。もしかしたら多少は「目に見える」ものがあるかもしれませんが、多くは目に見えないと思います。)
参考:『~用語:”目に見える”「メソッド・プロパティ・列挙(=Enum)・定数(=Const)」と右クリックメニューの画面の関係について~』
また、「オブジェクト」には、(前述しましたが)色んな「機能」が含まれています。
例えば単一のオブジェクトの場合、大分類的な言い方で言うと、プロパティ、メソッド、イベント、上下階層自由往来機能、上下階層機能流用機能、などです。
その中に、さらに、(例えば・・・・)
・色や大きさなどの属性(性質=性格)の設定機能、
・コピー・貼り付け・削除・新規作成、などの機能、
・データや数式の入力+保持機能
・プログラム自動実行機能
・表示/非表示の機能
・上下階層自由往来機能
・上下階層機能流用機能
など、があります。
以上は単一のオブジェクトの場合です。
コレクション(=コレクションオブジェクト)も、「オブジェクト」の仲間なので同様にそのような「機能」を持っています。
が、コレクションの場合は単一のオブジェクトよりも「限定的」です。
まず、イベントは持っておらず、しかし、プロパティ、メソッド、を持っています。
ただ、その量は、単一のオブジェクトたちと比べるとだいぶ少ないです。
それから、最初の注意事項なんですが、ヘルプや各種記事、市販書籍などでは「コレクション」なのか「単一オブジェクト」なのかの区別がつきにくいことがあります。
例えばヘルプでも、「Workbookオブジェクト」と「Workbooksオブジェクト」と書かれていることがあります。
これは、
「Workbookオブジェクト」は単一のオブジェクトのことをさし、
「Workbooksオブジェクト」はコレクションオブジェクトのことをさしています。
この場合は、複数形の「s」があるか無いかでコレクションオブジェクトか単一のオブジェクトかを判断し分けます。
市販の書籍やWeb記事などにも、「Workbooksコレクション」と書かずに「Workbooksオブジェクト」と書いてある記事が少なくないのですが、このような場合には、「あ!Workbooksオブジェクトって、s が付いているから単一のオブジェクトのことじゃなくて、Workbooksコレクションのことなんだな!」とエンドユーザー側で汲み取る必要があります。
規則等がないので無秩序でテキトーに「Workbooksオブジェクト」って書かれますから、私ら初心者にはいい迷惑なんですけど、エンドユーザーとしては注意が必要な個所です。
なお、コレクションの名前は、そのほとんどが「s」が単純に付くパターンなんですが、たまーに、ほんの少しだけ「is」が「es」になってたり、「y」が「ies」になってたりのパターンもあります。(これって英語と一緒でしたっけ?)
あと、「まんまでCollection とか Items って付加されるだけ」というものもあります。
なので、例えば・・・
「Axesオブジェクト」と書かれていたら、「単一のオブジェクトのことじゃなくて、Axesコレクションのことだな」とか、
「CustomProperties オブジェクト」と書かれていたら、「単一のオブジェクトのことじゃなくて、CustomPropertiesコレクションのことだな」とか、
「SeriesCollection オブジェクト」と書かれていたら、「単一のオブジェクトのことじゃなくて、SeriesCollection コレクションのことだな」とか
・・・などと判断する必要があります。面倒くさいですね(^^)
それから、画面上に見えるものをオブジェクト的に(=VBA的に)言い換えると次のようになります。
単一セル ←→ Rangeオブジェクト
単一のワークシート ←→ Worksheetオブジェクト
単一のブック ←→ Worksbookオブジェクト
コレクションの場合は目には見えませんが、以下のようになります。
セルの集まり=複数セル管理ロボット
←→Rangeオブジェクト
(コレクションではありませんが仕組みが似ています。
そして単一の場合と同じオブジェクトです。)
ワークシートの集まり=複数ワークシート管理ロボット
←→Worksheetsオブジェクト
=Worksheetsコレクション
=Worksheetsコレクションオブジェクト
ブックの集まり=複数ワークシート管理ロボット
←→Workbooksオブジェクト
=Workbooksコレクション
=Workbooksコレクションオブジェクト
ではまず最初に、単一オブジェクトたちとコレクションオブジェクトの関係のことを少しご説明しますと・・・
例えばワークシートで言うと
「Worksheet」オブジェクトが「単一のオブジェクト」で、
「Worksheets」オブジェクトが「コレクションオブジェクト」です。
=「Worksheets」コレクションは、単一のWorksheetオブジェクトたちの集まり、です。
=単一のWorksheetオブジェクトたちは「Worksheets」コレクションに含まれる形・・・となっています。
=単一のワークシートたちは「Worksheets」コレクションに含まれる形・・・となっています。
(※ このコレクションには「s」が付くだけなので見分け間違えないようにご注意を!)
(※ 「階層」としては、コレクションは「上位」でないけれど、でも、単一のオブジェクトたちはコレクションの中に束ねられて管理されています。ある意味「上下関係にはないけれど、横方向に主従関係・管理/被管理関係にあるイメージ」、って感じかも?です。
あるいは「コレクションは中2階に居るイメージ」・「コレクションは中2階に居て、単一オブジェクトたちを管理しているイメージ」と考えるほうがしっくりくる方は、そう考えてもいいかもしれません。いずれにしても、「オブジェクト式」の中では、コレクションだけで1階層分のスペースを占有することはありません。「コレクションと単一オブジェクトの共用」で1階層分のスペースが当てがわれています。ドットとドットのあいだの1階層分のスペース、に。)
↓ イメージ的には、「" 式 " としては」、以下のような階層構造なイメージです。
(トップの「Application」は単一オブジェクトで、コレクションはもとから
無いっぽいです。)
※2019/05/29追記
参考類似図:『DAOやADOのオブジェクトモデル一覧図(部分的なもの)』の、DAOやADOのオブジェクトモデルの階層一覧図。
(こんな図が見つかったので、あながち僕の考え方も、そうは間違ってはいなかったのかも・・・?と、少しホッとしています。^^ )
ブックで言うと
「Workbook」オブジェクトが「単一のオブジェクト」で、
「Workbooks」オブジェクトが「コレクションオブジェクト」です。
=「Workbooks」コレクションは、単一のWorkbookオブジェクトたちの集まり、です。
=単一のWorkbookオブジェクトたちは「Workbooks」コレクションに含まれる形・・・となっています。
=単一のブックたちは「Workbooks」コレクションに含まれる形・・・となっています。
=その全ての単一のブックたちに対して、「Workbooks」コレクションを通じてゴソっと
一括処理ができます。
(※こちらもコレクションには「s」が付くだけなので見分け間違えないようにご注意を!)
グラフシートで言うと
「Chart」オブジェクトが「単一のオブジェクト」で、
「Charts」オブジェクトが「コレクションオブジェクト」です。
=「Charts」コレクションは、単一のChartオブジェクトたちの集まり、です。
=単一のChartオブジェクトたちは「Charts」コレクションに含まれる形・・・となっています。
=単一グラフシートたちは「Charts」コレクションに含まれる形・・・となっています。
=その全ての単一グラフシートたちに対して、「Charts」コレクションを通じてゴソっと
一括処理ができます。
(※同上!ご注意を!)
「グラフの軸」で言うと
「Axis」オブジェクトが「単一のオブジェクト」で、
「Axes」オブジェクトが「コレクションオブジェクト」です。
=「Axes」コレクションは、単一のAxisオブジェクトたちの集まり、です。
=単一のAxisオブジェクトたちは「Axes」コレクションに含まれる形・・・となっています。
=単一の「グラフの軸」たちは「Axes」コレクションに含まれる形・・・となっています。
=その全ての単一の「グラフの軸」たちに対して、「Axes」コレクション通じてゴソっと
一括処理ができます。
(※同上!似てるのでご注意を!また、単なる「s付きの複数形」とも違うのでご注意を!)
なお、「セル」の場合には「単一オブジェクト」とか「コレクションオブジェクト」とかいう明確な差・違いは無いっぽいです。
セルの場合は、単一であっても複数集まっていても「Rangeのまま」なのですが、ただ、強いて「あくまでも」「イメージ」として言いますと・・・
Cellsプロパティを使って取得した「Range」オブジェクトが「単一のオブジェクト的」なイメージ・ニュアンスで、
Rangeプロパティを使って取得した「Range」オブジェクトが「コレクションオブジェクト的」なイメージ・ニュアンス、
・・・です。
※Cellsプロパティは、基本、すべてのセルか、単一セルしか選択(=取得)できません。
でも、Rangeプロパティは、すべてのセル、単一セル、だけではなく、
複数のセル(セル範囲)も選択(=取得)できます。
そして「Range」オブジェクトは、『 ” For Each ” 文を使って、指定した範囲の・複数の単一のセルたちに「ゴソっと一括処理」ができてしまう・・・ 』、というところが、コレクションの仕組みと非常によく似ています。
「For Each」文 は、繰り返し処理用(=ループ処理用)のステートメント(=制御文)です。
が、そもそも『 ” For Each ” 文は基本、「配列かコレクションに対して」しか使えません 』から(=もともとそういう仕様に決められていますから)、その意味でも・・・、
・「Rangeオブジェクトはコレクションの仕組みに似てる」
(単体の「セル」が複数集まったコレクション・・・的な感じ。)
・「Rangeオブジェクト自体が、コレクションと同じ、と思ってもいいのかも?」
・・・と、言えるのではないかと思いますし、もし間違っていたとしても、そう考えてしまうと、実際、セルの処理も少しラクになります。
また、「Ragneオブジェクト」は、「もとからセルが複数集まったコレクションオブジェクト的なもの。セル1個だけの時もあるだけで。」と敢えて理解してしまっても良いかとも思います。
※実は、バージョン2010には「Rangesコレクション」、というものが存在していますが、
まだよくわかっていません。すみません。
(2000にはありませんでした。2007以降にあるのかもですね。)
「セル」の集まり、ではなくて、「セルが集まったもの」が複数束ねられたもの、
という意味かも知れません。
勉強していません。すみません。
※さらに実は、(ニュアンスがちょっと違うのかもしれませんが、でも)、「Rangeオブジェクト」にも一応、(後述したように)「Item」プロパティが存在します。
その意味で、「Rangeオブジェクトはコレクションっぽい・似てる」、とイメージしてもよいのかもしれません。
後述しましたが、基本、コレクションはItemプロパティかItemメソッドのいずれかを持ちますので・・・。
(でも、Range.Rangeオブジェクトのような感じで使うっぽい、Itemプロパティなんですけど・・・。)
ここは僕も良くはわかってないので、あくまでも「なんとなく」の「イメージ」なのですみませんが・・・・。
【参考】
次の式は、両方とも、C3 セルの値を意味します。
Range("C3:E5").Item(1,1).Value
Range("C3:E5").Cells(1,1).Value
それから、「コレクション」を機能面から見ますと・・・、
「コレクションオブジェクト」とは、どのコレクションオブジェクトであっても・・・、
=主に、複数集めた単一オブジェクトたちを ごそっと一括処理する、新規の単一オブジェクトを作る、等々の、そいういった処理をラクに行うためのオブジェクト(=ツール=ユニット=ミニミニロボット。)
・・・・という感じです。
そういったことができます。
(一括処理だけでなく、もし名前やインデックス番号が分かるなら、コレクション経由で1つ1つの単独処理もできます。)
コレクションで「何ができるか」について、もう少し細かく言うと、例えば以下のようなことができます。
・単一オブジェクトたちを、「配列の各要素たち」、のようなニュアンスで扱う・処理
をすることができます。
その際はインデックス番号(Item番号)やNameプロパティのほうの名前などを
使います。(CodeNameプロパティのほうの「名前」ではなく。)
・上記の性質から、コレクションを介して、単一のオブジェクトを特定できます。
逆に言うと、単一のオブジェクトを特定する際は、そのほとんどが、
『いったん「目的の単一オブジェクトを束ねているコレクション」にアクセスし、
そのあとからの単一オブジェクトの選定・・・』、
という形になる・・・・、といえるかもしれません。
そして、その時の、そのコレクションにアクセスするための言わば「入り口」が、
「1つ上位の階層のオブジェクトが保持・内包している、かつ、
コレクションと同名のプロパティやメソッド等々(ややこしい!)・・・」
という感じなんだと思います。
ApplicationオブジェクトやWorkbookオブジェクト以外の
単一オブジェクトの取得(特定)では、多くがそんな恰好だと思います。
※ApplicationオブジェクトやWorkbookオブジェクトは、
CreateObject関数やGetObject関数、Newキーワードなどでも取得できるので。
・もし、単一オブジェクトの固有の「名前やインデックス番号(Item番号)」が
分からなくても、
「For Each」文(=ループ処理)を組み合わせて使うことで、
「コレクションの中のすべての単一オブジェクトに対して」、
一瞬でゴソっと一括処理できてしまう。
(例えば、すべての単一オブジェクトたちに対する、一括プロパティ設定や、
何らかのプロパティの値の一括調査・全調査・・・、メソッドの実行、などが
できます。
コレクションの中にどんな名前の単一オブジェクトたちがあるかを一覧させたり、
何らかの条件で単一オブジェクトたちの表示非表示をいっぺんに個別設定したり、
例えば単一のシートたちなら、何らかの条件でタブの色を いっぺんに個別設定
したり・・・、印刷するシートとしないシートを区分けしつつ一括印刷したり
・・・といったことができます。
「色んな条件別に・かつ・いっぺんに操作してしまいたい」、というような場合や、
あるいは、「メソッドだけでは対応できない細かい処理をさせたい場合」などに、
よく「For Each」文を併用するかもしれません。)
・また、コレクションによっては、
もし、単一オブジェクトの固有の「名前やインデックス番号(Item番号)」が
分からなくても、
さらには、「For Each」文(=ループ処理)を使わなくても、
「メソッド」と呼ばれる命令を使うだけでも、ゴソっと一括処理ができてもしまいます。
この場合、「ループ文」は使わずに、コレクションオブジェクトがもともと
保持・内包している「メソッド」と呼ばれる命令を使います。
その際は、例えば、一括印刷、一括コピー、一括削除、一括移動、一括選択、
一括可視・不可視、といったことなどができます。
もちろん、コレクションオブジェクトによって、できることは変わります。
(For Each 文のときとは異なり、無条件に・かつ・すべての単一オブジェクトたちを
処理してしまいたい、というときに、「メソッド」を使うことが多いかもしれません。
もちろん、メソッドとしてもともと組み込まれている命令しか使えませんが、でも、
「どうせ無条件に全部の単一オブジェクトたちに同じ処理するんだから、
わざわざ ” For Each ” 文を使わなくてもメソッドで処理してしまえば、
1行で済むし、変数設定も要らないよ?」
といったメリットもあるにはあります。)
・また、単一オブジェクトの固有の名前が分からなくても、インデックス番号(Item番号)
で、単一オブジェクトを特定・選択・指定ができる。逆もできる。
・コレクションの中に単一オブジェクトがいくつあるかを調べることができる。
・コレクションによっては・・、例えば「Addメソッド」という命令を保持・内包している
コレクションなら、それを使って、コレクションの中に、
新しい単一オブジェクトを作ることができる。
・単一オブジェクトの名前やインデックス番号(Item番号)が分かれば、一括処理
だけでなく、コレクション経由にて、単一オブジェクト毎の細かい処理もできる。
(ループでも、単独で1つずつでも可能。)
1つ具体例を示しますと・・・
たとえば、単一のそれぞれのワークシートたち(=個々のWorksheetオブジェクトたち)に対しての場合、
Worksheetsコレクションオブジェクト(=Worksheetsコレクションとも呼びます)を使って、以下のようなことができます。(ここでは主に、For Each文を使わない「全一括処理」についてだけ書きました。もちろん、インデックス番号などがわかるなら、For Each文などを使っての一括処理もできますし、また、ループ自体をしない「1つ1つへの単独の処理」もできます。)
・ループ文(For Each文)を使わずとも「Move」メソッドを使って、
すべてのワークシートをグラフシートの前後に全一括移動。
(先に、グラフシートが存在していないといけませんが。)
・ループ文を使わずとも「Copy」メソッドを使って、
すべてのワークシートを同一ブック内に全一括コピー、
あるいは、新規ブックを自動生成してその中に全一括コピー。
・ループ文を使わずとも「Delete」メソッドを使って、すべてのワークシートを全一括削除。
(グラフシートなどが別にあり、残っている場合、だけですけど。)
・ループ文を使わずとも「PrintOut」メソッドを使って、全一括印刷。
・ループ文(For Each文)と「PrintOut」メソッドなどを使って、
1シートずつ、何らかの細かい設定を変えながら全一括印刷する。
・ループ文(For Each文)とセルの色を設定するプロパティを使って、
すべてのシートの セルの色を「塗りつぶしなし」に全一括設定する。
・「PrintOut」メソッドを使って、全一括印刷。
このとき、例えば、「Worksheets.PrintOut」と書くと、すべてのワークシートを一括で印刷してくれます。
イミディエイトウィンドウでも実行できます。
(Worksheetsコレクションの場合は、「s」を書き忘れると単一のWorksheetオブジェクトを指定したことになってしまい、エラーになってしまうのでご注意ください。)
ただ、この場合すべて印刷されるのは、ワークシートだけで、グラフシート(Chartsオブジェクト)までは印刷されません。
ちなみにですが、多くのコレクションオブジェクトで以下のようなプロパティやメソッドを保持・内包しています。
【ほとんどのコレクションが保持・内包しているもの】
・Applicationプロパティ(そのコレクションを持っているアプリケーション)
※Parent.Parent.Parent・・・しなくてもいきなりトップまでさかのぼれる。
・Countプロパティ
(「コレクション内に含まれる単一オブジェクト」の総数チェックに使います。)
・Itemプロパティ、か、Itemメソッド、のいずれか。
(単一オブジェクトを名前かインデックス番号で特定する時に使います。
省略可能なのでほとんどの場合、省略されます。
例えば、「 Worksheets.Item("Sheet1") 」は、ほとんどの場合、
「Item」が省略されて、「 Worksheets("Sheet1") 」と記述されます。
ピボットテーブルの場合は、Itemメソッド、ですが、
「Activesheet.PivotTables(1)・・・」のように、これも、
省略されて記述されます。)
※なぜプロパティもメソッドも、同じような動きをするのに、
プロパティやメソッドという形に別れているのか?は、
僕にはわかりません。すみません。
【 ” 印刷できる ” コレクションが保持しているもの(Charts、Sheets、Worksheets)】
・Visibleプロパティ(表示/非表示)
・Parentプロパティ(親オブジェクトのチェック)
・Addメソッド(新規作成)
・Moveメソッド(全一括移動) ※異なる種類のシートの前後に一括移動。
・Deleteメソッド(全一括削除) ※シート等の場合は異なる2種類以上のシート等が必要。
シート等がゼロの状態にはできないので。
・PrintOutメソッド(全一括印刷)
・PrintPreviewメソッド(全一括プレビュー。1つのプレビューウィンドウに
すべての指定シートの内容が、複数ページにわたって表示されます。)
・Selectメソッド(全一括選択)
※印刷できるコレクション以外でも、ここに挙げた以外の、共通するプロパティやメソッドが存在します。
※また、コレクションではなくて、単一のChartオジェクト、単一のWorksheetオジェクトなどにも、同名の、
・Visibleプロパティ(表示/非表示)
・Parentプロパティ(親オブジェクトのチェック)
・Moveメソッド(全一括移動)
・Deleteメソッド(全一括削除)
などが存在します。
が、名前は同じですが、機能・動きが少し異なります。
基本・コレクションのプロパティやメソッドは「全ての単一オブジェクトに対する ” 全一括処理 ” 」ですが、それに対して、「単一オブジェクトの同名のプロパティやメソッド」は、個々のその単一オブジェクトを、1つ1つ個別に処理します。
例えば、
Worksheets.PrintOut
と書くと、この「Worksheets」はコレクションなので、「PrintOut = 全一括印刷」の意味となります。
For Each 文無しに、すべてのワークシートが印刷されます。
※VBAでは「名前は同じだけどまったくの別物」、ということが非常に多いので誤解・混同をしないようによくよく注意してください。
そして、誤解・混同しないためには「階層構造全図」のおおまかな使い方が理解でき、ヘルプやオブジェクトブラウザが扱えることが必須です。
※コレクションかそうでないかの判断は、「プロパティの後ろにカッコがあるか無いか」、
で判断できます。
基本、コレクションを指定する場合、「コレクションと同名のプロパティ」の
記述のあとに、カッコを「書きません」。
逆に、もし単一のオブジェクトを指定する場合は、カッコを付けて、その中に目的の
単一オブジェクトの名前かインデックス番号を書くことになっているからです。
それがVBAの決まりです。
プロパティ記述の後にカッコがない、ということは当然、
「単一オブジェクトを表す固有の名前や番号が無い」、ということでもあるので、
その場合は、自動的・かつ・暗黙的に、「コレクションを指定しましたよ」
となるのが、VBAの仕様・もともとの決まりごと、ですのでそのように判断します。
※プロパティ記述とカッコのあいだには前述した「Item」が省略されています。
【例】
ActiveWorkbook.WorkSheets とだけ書いた場合
→ 操作対象として、「WorkSheetsコレクションオブジェクト」を
指定(選択)したことになります。
これは、「ブック内のすべてのワークシートを一括選択した」ようなイメージです。
例えば、新規ファイルを作った直後なら、もしバージョンが2010以前なら、
Sheet1、Sheet2、Sheet3、の「3つのシートすべて」
(=3つのWorksheetオブジェクトすべて)を「一括選択」したイメージです。
ActiveWorkbook.WorkSheets("Sheet1") と書いた場合
→ 操作対象として、「Sheet1」という名前の、
「単一の」「WorkSheetオブジェクト」「だけ」を、
それ「一つだけ」、を、指定(選択)したイメージになります。
(「WorkSheetオブジェクト」と書いたときは、
コレクションの場合と違い、「WorkSheet」には
「s」が無いことに着目してください。)
※ここでの「WorkSheets」は、コレクション名と同名の「WorkSheetsプロパティ」
です。「WorkSheetオブジェクト」の1つ上位(=親)の階層となる、
「Workbookオブジェクト」が保持・内包しているプロパティです。
また、「WorkSheetsプロパティ」は、それ1つだけで、
WorkSheetsコレクションか、単一のWorkbookオブジェクトか のいずれかを
取得できるプロパティです。
(「取得」=厳密には違いますが、操作対象として選択・指定する・・・
みたいなニュアンスです。)
上記の最初の例のように「WorkSheets」のあとにカッコも何も記述しなければ、
「コレクションオブジェクト」を取得(=選択・指定)したことになりますし、
一方、「WorkSheets」のあとにカッコを付けてシート名やインデックス番号も
記述すれば、その名前の単一のシートを取得(=選択・指定)したことになります。
もともとそういう仕様になっています。
いっぽう、
Worksheets(2).PrintOut とか、
Worksheets(3).PrintOut など、
と書くと、この「Worksheets」はコレクションを指定したのではなく、(2)とか(3)とか書いたことによって「個別のWorksheetオブジェクト=つまり個別のワークシートを指定した」ということになりますので、「PrintOut = 個別印刷」の意味になります。
それぞれ、「1つだけのWorksheetオブジェクト=1つのワークシートだけ」に対する印刷となります。
(カッコが付いていて、そのカッコの中にインデックス番号を書いて、1つのワークシートを指定していますので。)
なので例えば、「For Each」文とカウンタ変数「i」を使って
Worksheets(i).PrintOut
などと書いたときも、(i)というインデックス番号によって単一オブジェクトを指定した、ということになるため、コレクションのほうのPrinOutメソッドを使ってはおらず、単一オブジェクトのほうのPrinOutメソッドを使っている・・・ということになります。
このように同じ名前のプロパティやメソッドでも、親オブジェクトが変わると動きが少し異なりますので「混同しないように」ご注意を。
「親オブジェクトが変わる」とは・・・
Worksheets.PrintOut と書いた時 は、
→ 親オブジェクトが「Worksheetsコレクションオブジェクト」、
「=複数のすべてのシート」になったことを意味しています。
それが、
Worksheets(i).PrintOut とか
Worksheets(2).PrintOut とか
Worksheets(3).PrintOut とか
Worksheets("Sheet1").PrintOut などと書いた時 は、
→ 親オブジェクトが、それぞれの名前や番号を示す「Worksheetオブジェクト」、
「=それぞれの名前や番号を示す、単一のシート1つだけ」に変わったことを
意味しています。
「親オブジェクトが変わる」とは、そのような意味です。
そして、
「複数のすべてのシート一括」に対して、
と、
「それぞれの名前や番号を示す、単一のシート1つだけ」に対して、
では、
当然、「やれること」「できること」も変わってきます。
といいますか、操作対象が変わる・異なるのですから、そもそも「同じことはできません」。
また、基本、コレクションは、Itemプロパティか、Itemメソッドのいずれかを保持・内包しています。
なので、オブジェクトブラウザで「Item」で完全一致で検索すると、ItemプロパティとItemメソッドが検索され、その親オブジェクトは、(多分ですが)そのすべてが「コレクション」です。
それを見ていくと分かるのですが、多くの「コレクション(=コレクションオブジェクト)」は、保持しているプロパティやメソッドが似ています。
また、単一のオブジェクトは割とたくさんのプロパティやメソッド、また、イベントを保持していますが、コレクションオブジェクトではそれらの数がメッチャ少ないか、少なめです。
あと、「オブジェクト式・オブジェクトモデルの階層構造」とコレクションとの関係のお話をしますと・・・
例えば、オブジェクト式・オブジェクトモデルの階層構造で言うと、コレクションと単一オブジェクトの関係は以下のような感じだったりします。
Application単一(ドット=1階層分の区分け)
|
|_Wordbooksコレ_Wordbook単一( . )
|
|_Worksheetsコレ_Worksheet単一( . )
|
|_Range(コレ的)( . )
|
|_Range(コレ的)
※コレクションオブジェクト、単一オブジェクト、それぞれに、それぞれのプロパティやメソッドが内包されています。
※参考
ちなみにですが、イミディエイトウィンドウでは以下のような調査ができました。
? TypeName(Worksheets.Parent)
Workbook
? ActiveWorkbook.Worksheets.Parent.Name
Book1
? TypeName(Worksheets("Sheet1").Parent)
Workbook
? ActiveWorkbook.Worksheets("Sheet1").Parent.Name
Book1
「Worksheets」はコレクションを表し、「Worksheets("Sheet1")」は「Sheet1」というワークシート単体を表しています。
「Parent」は「親オブジェクト」=「1階層上位のオブジェクト」の意味で、「TypeName関数」はオブジェクトの型(種類)などを調査できる関数です。
その結果、「Worksheets」コレクションも「Worksheets("Sheet1")」単体も、どちらも親オブジェクトの種類は「Workbook」であり、しかも、その名前は「Book1」です。
ここからもやはり・・・、
『「Worksheets」コレクションは「Worksheets("Sheet1")」単体の「親ではない」。
また、親が同じなんだから 両者は同じ階層に居るのでは・・・? 』
というイメージとなる・・・
・・・と、感じて頂けると思います。
「単一オブジェクトの取得」(取得=呼び出し=選択=選定)、については・・・、
・「目的のオブジェクトの1階層上位(1ドット分上)のオブジェクト」の
プロパティやメソッドを使って(=それらを入り口にして)、
・目的の単一オブジェクトを含んでいる「コレクションオブジェクト」にアクセスし、
・その中から、「単一オブジェクト」を選び出す・・・
・・・という感じで「単一オブジェクトの取得」を行っています。(上図参照)
これは、Excel2000~2003のヘルプの、オブジェクトモデルの階層構造の全図がこんな感じになっています。
マイクロソフトのサイトには別口で以下のような図式もしてありますが、でもそれだと「( . なし)」のような部分・箇所ができてしまいます。そうなりますと、「オブジェクト式としては1つのコレクションだけで1階層分を消費しているわけではない」ということになりますので、(この図では)オブジェクト式と同じような形態・イメージでリンクさせて見ていくことができません。
なので、前出の上図のようにとらえるほうがいいと思います。
Application単一(ドット=1階層分の区分け)
|
|
|
|_Wordbooksコレクション( . なし)
|
|_Wordbook単一( . )
|
|
|
|_Worksheetsコレクション( . なし)
|
|_Worksheet単一( . )
|
|
|
|_Range(コレ的)( . )
|
|
|_Range(コレ的)
つまり、
単一のWordbookオブジェクトがWordbooksコレクションに含まれるのは間違いないけど、
オブジェクト式としては、Wordbooksコレクションにドットは付かないので、
「両者は同じ階層にある」とイメージしてもよい。(さほど問題は無い。)
(ヘルプには「単一オブジェクトはコレクションのメンバ」、と書いてあるので)
現実・厳密には間違いだったとしても、でも、それでも、「敢えて」、で。
「単一のWordbookオブジェクトは、Wordbooksコレクションに含まれない」と、
考えるわけではないので。
あくまでも、「階層は同じであっても、横方向に並びあっていたとしても、
単一のWordbookオブジェクトはWordbooksコレクションに含まれる」と考えるので。
と考えて良いのだと思います。
少なくとも、そのほうが、階層構造全図と「オブジェクト式のドット(= ” 1階層分 ” という単位)」の役割を、リンクさせて考えることができるので、それでもいいと思います。
なお、コレクションから単一オブジェクトを取得するには、前述のように、
・上位のオブジェクト(1階層上のオブジェクト)のプロパティやメソッドを使って、
(それを入り口に)目的の単一オブジェクトのコレクションにアクセスして取得する。
ということが割と多いですが、
その場合、その「プロパティやメソッド」は・・・・、
というか、「プロパティであろうが、メソッドであろうが」、
「オブジェクトを返す自作関数」と同じような構造・仕組みなっていると考えてしまってよい・・・
と考えてもOKだと思います。
これは、VBAを理解するうえで、「超・重要」、なことですので、絶対に意識しておいてください。
厳密には違うかもしれませんが、でも、特にオブジェクトブラウザを見る・読むときに、その考え方が絶対に必要になります。
逆に言うと、それを理解できないと、VBAは理解できない、と思ってください。
すくなくとも「自力でのエラー解決」がまったくできないか、10~100倍、遅くなります。
もちろん、Q&Aサイトで質問しても、多くは回答者の言っていること・コードそのもの、を理解できません。
そんな風にならないように、
「プロパティであろうが、メソッドであろうが」、
「コレクションから単一オブジェクトを取得する際には」、
「オブジェクトを返す自作関数」と同じような構造・仕組みになっていると考えてしまってもよい・・・
と考えてみてください。
その意味で、「値やオブジェクトを返す自作関数」を作れるようになることは
「VBAが初級以上に上達するためには必須!」であるとも言えます。
===================
※★★★ 超超超・重要事項!!!★★★ →→→ 1階層「上位」=親、1階層「上位」のオブジェクト=親オブジェクト、なんですが、コレクションオブジェクトは単一オブジェクトの「親」=「上位」という位置関係にはありません。
そして、階層が「親であること=1階層分、上であること」と、「複数の単一オブジェクトたちを束ねる・含む(束ねて管理しているだけ)」ということ、実は「まったくの別の事柄・べつもの」であり、もっと言うとまったくの「無関係」です。
このことは、VBAの学習(特に独学)にとって、「超重要事項」ですので、必ず意識しておきます。
でないと、ヘルプとオブジェクトブラウザの意味が通じなくなってしまう(=読めなくなってしまう)からです。
コレクションオブジェクトは、「複数の単一のオブジェクトを束ねる機能・単一オブジェクトたちをゴソと一括処理する機能」を有してはいますが、束ねてはいますが・でも・「親」の位置には「居ない」のです。「兄弟」的な位置に居るイメージです。
「兄弟」的な位置、「同じ階層」に居つつ・・・、でも、複数の単一オブジェクトたちを束ね・含み・管理している・・・というイメージです。
それは「オブジェクト式」の「ドット」の位置・・・、といいますか、「ドットからドットまでの間に記述されているもの」、を「よく観察」すれば、おそらく多くの方が「言われてみると確かにそうなっている・・・」とイメージ・実感できるのではないかと思います。
※2020/02/18追記:以下、間違っていました。すみません。
もともと、VBAにおける、オブジェクト式における、「1階層分」とは、「ドットからドットまで!」を指します。
もしコレクションオブジェクトが、単一オブジェクトの「1つ上の階層」に位置することになっているのであれば、コレクションだけででもドットからドットまでが占有されていないといけません。つまり、コレクションと単一オブジェクトの間にドットが無いといけない、ということになります。逆に、もしそうなっていれば『 コレクションは単一オブジェクトの「親」だ 』と言えます。
でも現実にはそんな風になってはいません。
例えばコレクションを指定したいときはカッコや引数を書かず、一方、単一オブジェクトを指定したいときはカッコや引数(名前やインデックス番号)を書く、という風に、「書き分けの違いがあるだけ」で、ドットからドットまでにもうひとつ、「コレクションの階層専用のドット」が入る・増えるわけではありません。
繰り返しになりますが、VBAにおける、オブジェクト式における、「1階層分」とは、「ドットからドットまで!」を指します。
上記の記述は間違いでした。すみません。
ドットは、「階層の切れ目」を表現しているのではなく、「オブジェクトの切れ目」、を表現しているのでした。
各コレクションにおける、「Item」という名前のプロパティやメソッドのことを学習していなかったために、上記のような理解のし間違いをしてしまっていました。
ごめんなさい。お詫びします。
「ドットは基本、オブジェクトの切れ目」です。
「階層の切れ目」は、「 ”下位のコレクションオブジェクト” を取得するプロパティ+ドット+ItemプロパティorItemメソッド」がひとつの階層の区切りです。
ただ、コレクションを持たない単一オブジェクトもあるので、例外もあります。
が、多くは、
「Workbooks.Item("ブック名")」とか、
「Worksheets.Item("シート名")」とか、
「Charts.Item("グラフシート名")」とか、
「Pivottables.Item("ピボットテーブル名")」
といった感じで、
「Item」とセットになったところまでが含まれて、Item(××)の次のドットが、「階層の区切り」です。
ただ、「Item」は多くのサンプルで(ヘルプのサンプルでさえ)省略されるので、このことがとても発見しにくいです。気づきにくいです。
「コレクションは複数の単一オブジェクトを含んでいる」「単一オブジェクトたちはコレクションに含まれている」という表現がよくなされます。当サイトでもそういう言い方をよくしますが、でも、だからといって、コレクションが単一オブジェクトの「親=1階層分、上」に位置しているわけではないのです。同じ階層(あるいは別の空間)に居る感じです。同じ階層(あるいは別の空間)に居つつ、単一オブジェクトたちを含み、管理しているイメージです。
そう、「含む」というより、「束ねて管理しているだけ」というイメージのほうが強いと思います。
(その証拠と言っては何ですが、たとえば「Sheetsコレクションオブジェクト」なんて、階層構造を全く無視して、ワークシートもグラフシートも含んで束ねて管理してしまっています。WorksheetオブジェクトやChartオブジェクトは同じ階層に居てお互いに上下関係は無いのに、両方をいっしょくたに管理しています。)
コレクションが単一オブジェクトの「1階層上」のオブジェクトだと誤解すると、VBAのオブジェクト構造の全体像がわからなくなり、オブジェクトブラウザやヘルプも読めなくなります(=意味が通じなくなります。)
なお、(前述しましたが)多くの「単一オブジェクト」のヘルプページには「単体のオブジェクトはコレクションのメンバです」と書いてあるので、もしかしたら、「コレクションにこそ階層が存在して、単体のオブジェクトには、実は、階層は存在しない」、という構図が「正しい姿」のかもしれませんが、でもそう理解してしまうとヘルプとオブジェクトブラウザ・・・、特にオブジェクトブラウザが読みにくくなるのと、あと、「TypeName関数やParent」を使っての「親オブジェクト調査」の結果や「ローカルウィンドウでの親オブジェクトや子オブジェクトの調査」なども利用しづらくなってしまうので、僕は「コレクションには階層は無くて、単一オブジェクトにある」という風にあえて理解してしまっています。
実際、それでもさほど困らないし問題ならない気がするので、それでもいいと思うのです。(コレクション/単体、どちらに階層構造が直結していても、オブジェクト式のドットが増えるわけでもないので。)
繰り返しになりますが、イミディエイトウィンドウでは以下のような調査ができました。
? TypeName(Worksheets.Parent)
Workbook
? ActiveWorkbook.Worksheets.Parent.Name
Book1
? TypeName(Worksheets("Sheet1").Parent)
Workbook
? ActiveWorkbook.Worksheets("Sheet1").Parent.Name
Book1
「Worksheets」はコレクションを表し、「Worksheets("Sheet1")」は「Sheet1」というワークシート単体を表しています。
「Parent」は「親オブジェクト」=「1階層上位のオブジェクト」の意味で、「TypeName関数」はオブジェクトの型(種類)などを調査できる関数です。
その結果、「Worksheets」コレクションも「Worksheets("Sheet1")」単体も、どちらも親オブジェクトの種類は「Workbook」であり、しかも、その名前は「Book1」です。
ここからもやはり・・・、
『「Worksheets」コレクションは「Worksheets("Sheet1")」単体の「親ではない」。
また、親が同じなんだから 両者は同じ階層に居るのでは・・・? 』
というイメージとなる・・・
・・・と、感じて頂けると思います。
結果(またまた繰り返しになりますが)、階層が「親であること=1階層分、上であること」と、「複数の単一オブジェクトたちを束ねる・含む(束ねて管理しているだけ)」ということ、実は「まったくの別の事柄・べつもの」「無関係」と考えるほうがいいと思います。そうすれば、オブジェクトブラウザやヘルプが読めるようになります(=意味が通じてきます。)