『たった1秒で仕事が片づくExcel自動化の教科書』(技術評論社)にて、
紙面の都合で書けなかった詳細をこちらで解説します。
■RangeとCellsの使い分けについて
一言で言うと、変数を使う場合はCells、使わない場合はRangeということになります。
変数を使わない場合にCellsを使うことは問題ありませんが、Rangeに変数を使う次のような書き方はおすすめしません。
Range("A" & i) |
一般的な書籍では普通に紹介されている書き方ですが、ちょっと強引な印象を受けます。
印象の問題で済むならいいのですが、次のようなことを考えてみてください。
For Next構文でセルにデータを連続入力する際、列方向に入力していくならこの書き方でも書けます。
つまり行数に変数を使う場合はまだいいです。
一方、列数に変数を使う場合はどうなるでしょうか。
つまり行方向…例えば、A1セル、B1セル、C1セル…という順番に入力する際はこれだとややこしくなります。
Cellsであれば
Cells(i,1) |
と書けば済みます。
このように、変数を使う場合はCells、Rangeは変数を使わないセル指定に使う、
という使い分けを知っておくと不要な迷いがなくなるということです。
一方、セル範囲指定に変数を使う場合はRangeとCellsを組み合わせます。
(例) Range(Cells(1,1),Cells(i,j)) |
実はRangeとCellsは深堀りすると果てしなく深い話になります。
以下、本当にお暇な時にお読みください。
すごい改善専務、山岡さんの講義です。
~~~~
まずは基本。
A1セルに"エクセル"と入れる場合。
Range("A1").Value="エクセル" Cells(1, 1).Value="エクセル" |
A1~B2セル(4つのセル)に"エクセル"と入れる場合。
Range("A1:B2").Value="エクセル" Range(Cells(1,1),Cells(2,2)).Value="エクセル" |
RangeもCellsもセルに対して、何らかの操作をする場合に使用します。
多くのプロパティ、メソッドが用意されていますが、これらの、プロパティ、メソッドを調べるのは簡単です。
「マクロの記録」で、セルを操作すれば良いのです。記録されたマクロの必要な記述をコピペして使えばOKです。
注意).ネットでは、書式設定に、NumberFormatを使用している場合を見かけますが、
自動記録される、NumberFormatLocalを使うべきです。
■Range
RangeはWorksheetオブジェクトのプロパティで、セルまたはセル範囲を表すRange オブジェクトを返します。
ヘルプではこう書いてあります。
========
セルまたはセル範囲を表す Range オブジェクトを返します。
expression.Range(Cell1, Cell2)
Cell1 必ず指定します。
バリアント型 (Variant) の値を範囲の名前を指定します。
これは、マクロの言語の A1 形式での範囲である必要があります。
範囲名には、範囲を表す演算子 (:)、共通部分を表す演算子 (スペース)
または複数の範囲を表す演算子 (,) を含めることができます。
また、ドル記号 ($) は含めることはできますが、無視されます。
範囲の一部にローカルに定義した名前を使用できます。
名前を使用する場合、その名前はマクロの言語と見なされます。
Cell2 省略可能です。
バリアント型 (Variant) の値を使用します。
セル範囲の左上隅と右下隅のセルを指定します。
各引数には、単一のセルを含む列全体あるいは行全体を表す Range オブジェクト、
またはマクロの言語で単一のセルに名前を付ける文字列を指定できます。
========
絶対に分かりませんよね、私も読んで理解できません。(笑)
だから、書店には、入門書が並んでいるのでしょう。つまり、言葉にすると結構難しいのです。
では指定方法のパターンを紹介します。
1. Range("A1")→A1セル
2. Range("A1:B3")→A1~B3セル範囲
3. Range("A1,B3")→A1とB3セル
4. Range("A1", "B3")→A1~B3セル範囲
5. Range(Cells(1, 1))→A1セル
6. Range(Cells(1, 1), Cells(3,2))→A1~B3セル範囲
7. Range("A1", Cells(3,2))→A1~B3セル範囲
8. Range("A1:A3", "B1")→A1~B3セル範囲
9. Range("名前定義")→名前定義のセル範囲
10. Range(Rows(1), Rows(3)) →1~3行の範囲
11. Range(Columns(1), Columns(3)) →1~3列の範囲
12. Range("1:3") →1~3行の範囲
13. Range("A:C") →1~3列の範囲
14. Range(Rows(1), Columns(1)) →全セル
まだまだ指定方法はあるでしょうが、まあこんなところにしましょう。
太字は必ず覚える必要があるもので、VBAで実際によく使います。
それ以外は、覚える必要も無いし、使う事もないと思います。(使ってもよいですけどね)
特に8.や12.などは、悪ふざけの範囲です。でもエラーにはなりません、そしてそれが問題です。
VBAでバグにより結果的にこのような指定になってしまい、とんでも無い事になる場合があります。
Rangeは、セル範囲(複数セル)を扱う時に使用します。
もちろん単一セルでも使いますが、その場合は、行列を指定するCellsを使う方が多いです。
また、Rangeオブジェクトに対し、プロパティを指定しない場合は、Valueプロパティが規定となります。
■Cells
CellsはWorksheetオブジェクトまたはRangeオブジェクトのプロパティで、
セルを表すRangeオブジェクトを返します。
ヘルプでは次のように書かれています。
======
CellsプロパティをRange オブジェクトに指定した場合
指定した範囲のセル (Range オブジェクト) を返します。
値の取得のみ可能です。
expression.Cells
expression 必ず指定します。
Range オブジェクトを返すオブジェクト式を指定します。
CellsプロパティをWorksheet オブジェクトに指定した場合
ワークシートのすべてのセル (Range オブジェクト) を返します。値の取得のみ可能です。
expression.Cells
======
これも全くもって、理解不能な説明です。
では指定可能なパターンです。
1. Cells →全セル
2. Cells(1, 1)→ A1セル
2. Cells(1, "A") →A1セル
Cellsの指定方法はあまりありません。
普通にCells(行, 列)で指定すれば良いです。
また、ヘルプで「値の取得のみ可能」と言うのは、WorksheetオブジェクトのCellsプロパティとしての説明です。
まず、理解すべきは、Cellsオブジェクトと言うのは存在しない事です、
CellsはRangeオブジェクトを返します。
つまり、WorksheetのCellsプロパティは、シートの全セル範囲のRangeオブジェクトです。
おそらく、この部分の理解が不足していることが多いのだろうと思われます。
Cellsプロパティは、シートの全セル範囲のRangeオブジェクトなのですから、
その行列の位置を指定することで、単一セルになるのです。
おそらく、他言語をやっている人なら、Cells.Item(1, 1)の指定の方がしっくりくるかもしれません。
そして、これが本来の指定であり、Cells(1, 1)は、この省略形とも言えます。
また、Rangeオブジェクトなので、プロパティを指定しない場合は、Valueプロパティが規定となります。
■RangeとCellsの極み
セル「C3」を指定する場合のパターンです。
1. Range("C2")
2. Cells(3, 3)
3. Cells.Item(3, 3)
4. Range("B2:C10").Cells(2, 2)
5. Range("B2:C10").Item(2, 2)
6. Range("A1").Cells(1, 3).Cells(3, 1)
上の2つは普通の指定ですよね、でも下の3つは何でしょう。
実際に使用することはありません。
ただ、これらが全て同一セルを指すことを理解するには、
Rangeオブジェクト、Cellsプロパティを正しく理解している必要があります。
6.に関しては、オブジェクトの参照についても理解する必要があります。
Range("A1").Cells(1, 3)は、C1セルになり、CellsはRangeオブジェクトなので、
さらに、.Cells(3, 1)で、C3セルを指す事になります。
Offsetと同じです、OffsetもRangeオブジェクトを返すプロパティです。
ただ、こんな使い方をすることは無いので、覚える必要はありません。
ただ、これが原因で、意味不明なバグで悩む事もあると言う事を知っておいて下さい。
つまり、Rangeを引数で渡した場合に、その範囲を超える指定をしても、動作してしまうのです。
・・・ちょっと難しいですね、あくまで、理解を深める為のお話です。
■Rangeオブジェクトのお話
Rangeオブジェクトを理解するためのたとえ話です。
以下を想像して下さい。
碁盤の目に区切られた場所があり、マス目は、横にA,B,C、縦に1,2,3と見出しが付いています。
その1マス毎に、ダンボールが置いてあり、そのダンボールは、
・それぞれ大きさも、色ももまちまちです。
・それぞれの中には、色々な物が入っています。
・それぞれに、小人が沢山付いています。
・直接ダンボールにふれることも、動かすこともできません。
・こちらで解るのは、ダンボールに備え付けられている電話番号だけです。
・この電話は、他の箱に転送可能です。
・ダンボールに何かをしたい場合は、電話をかけ、小人に指示します。
どうです、想像できましたか?奇妙な光景です。(笑)
このダンボールがオブジェクト、小人がプロパティやメソッド、電話番号がアドレスです。
ダンボール("A1")が左上のダンボールになりますが、ダンボールを持てるわけではありません。
ダンボール("A1")は、左上のダンボールの電話番号でしかありません。
中身を知るには、小人のValueさんに電話で聞くしかありません、それがダンボール("A1").Valueです。
色を変えるには、小人のInteriorさんを通し、部下の小人のColorさんに、電話で指示します。
また、ダンボール("A1:B2")とすると、A1,A2,B1,B2へ同時に電話する事が出来ます。
ダンボール("A1")に電話し、続けてOffset(1,1)と伝えると、
ダンボール("A1")への電話は、1つ下、1つ右、の箱に転送されます。
従って、ダンボール("A1").Offset(1,1)は、ダンボール("B2")に電話しているのと同じことです。
Set 変数 = ダンボール("A1")は、電話番号を変数に入れているだけです。
結果として、ダンボール(1,1)に対する指示も、変数に対する指示も同じことになります。
ははは、って感じですが、これが私の頭の中でのRangeオブジェクトの想像図です。
少しは、イメージできましたでしょうか。
気味が悪い、余計解んないって・・・
個別のプロパティを説明しなくても、これだけの説明が必要です。
Rangeオブジェクトのプロパティ、メソッドはVBAの基本です。
書式設定、行高、列幅・・・VBAでは必須知識になります。
また、前回も出た、Findは、Rangeオブジェクトのメソッドです。
ネット上では、RangeとCellsで速度がどうとか・・・
というのも見かけますが、少し話が変な気がします、
普通には、差異はないはずですし、厳密な速度測定なら、全述のItemの指定による速度の違いも考慮すべきです。
いろいろ難しいですが、エクセルですから、結局は、このRangeに対する操作が全てです。
どのようなプロパティ、メソッドがあるかは、折を見て調べておく事は、大変役に立つと思います。
私もまだまだ、知らないプロパティ、メソッドは沢山あります。
『たった1秒で仕事が片づく Excel自動化の教科書』執筆陣が自ら直接指導。
実務直結・一日集中・受講後無期限サポート付きのマクロVBAセミナー