RangeオブジェクトとRangeを返すプロパティ

ここまでは「転記」の実際を説明しましたが、Rangeオブジェクトを理解すると展開が変わるので必見です。
重要なことですが初心者にはハードルが若干高いことも事実です。 たとえば「計算式」「相対参照・絶対参照」A1参照形式・R1C1参照形式」を一生懸命説明したつもりですが、結局自社内でもこの説明での理解度はいまひとつで、自分でも不満な状態です。
ここでRangeオブジェクトとRangeを返すプロパティ」の説明をするのもうまく伝わるか判りませんが、大事なことなので、是非、よくお読み下さい。
ここまでの説明であるように、
自動記録に始まって「Rangeオブジェクト」は初心者でも結構気楽に使われており、
    Range("A1")
と書けば「Rangeオブジェクト」がマクロのコードで直接つかめると思っている人も多いでしょう。

そのように理解されていても「矛盾」に気が付くことなく、問題ないままで進められてしまうこともあります。

でも、ここには2つの「誤解」が含まれています。
1つは、
上のサンプルは「Rangeオブジェクト」を直接つかむ記述ではないということです。
Rangeオブジェクト」をヘルプで調べると、
Rangeオブジェクトの使い方 Rangeオブジェクトを取得するプロパティ、およびメソッドを次に示します。
Rangeプロパティ
Cellsプロパティ
RangeプロパティおよびCellsプロパティ
Offsetプロパティ
Unionメソッド
と記載されているように、あくまで上記の記述は「Rangeプロパティ」を記述することで、「Rangeオブジェクト」の参照を取得しているのであって、「Rangeオブジェクト」を直接取得しているのではないのです。
Option Explicit

Sub TEST()
    MsgBox Range("A1").Value
End Sub
と記述するのは、実際は内部で「Rangeプロパティ」から「Rangeオブジェクト」が取得し直されているわけで、
Option Explicit

Sub TEST()
    Dim objR As Range
    Set objR = Range("A1")
    MsgBox objR.Value
End Sub
このような記述の変数取得を省略した形にしていることなのです。

中には「Cellsプロパティで記述する方が遅い」などと言っている人がいるようですが、「転記の記述方法による処理時間の比較」で示している通り大きな違いはなく、逆に速いこともあります。

もう一つは、つかんでいる「Rangeオブジェクト」は「実体」ではなく「オブジェクトの参照」だということです。
でもこれは誤解したままでも問題ないように思います。実際、「Rangeオブジェクト」をつかんでしまえば、それに対するメソッドやプロパティを操作できることには変わりません。
前置きはこのくらいにして、
実際にシートやセルの操作を、「Rangeオブジェクト」を取得することを意識してやってみましょう。
新規ブックでRangeオブジェクト操作をやってみる。

まず、セルやセル範囲である「Rangeオブジェクト」からはいろいろな情報がつかめることを念頭に置いて下さい。
たとえば、このように記述すると、
Option Explicit

Sub TEST1()
    MsgBox Range("A1").Value & vbCr & _
           Range("A1").Address & vbCr & _
           Range("A1").Row & vbCr & _
           Range("A1").Column & vbCr & _
           Range("A1").RowHeight & vbCr & _
           Range("A1").ColumnWidth
End Sub
実行してみると、
マクロ「TEST1」の結果
このように処理結果が表示されます。(各プロパティの内容はヘルプで確認して下さい。)

でも、この記述では合計6回同じセルに対して、内部で「Rangeプロパティ」から「Rangeオブジェクト」の参照が取得し直されているということになるのです。
もちろん、この程度の記述で処理時間に影響が出ることはないでしょうが、大きな処理でもいつもこのような記述をしていると処理時間に影響が出ることも考えられます。
ならば、「Rangeプロパティ」から「Rangeオブジェクト」の参照を取得する記述部分を1回でまとめてしまいましょう。
Sub TEST2()
    Dim objR As Range
    Set objR = Range("A1")
    MsgBox objR.Value & vbCr & _
           objR.Address & vbCr & _
           objR.Row & vbCr & _
           objR.Column & vbCr & _
           objR.RowHeight & vbCr & _
           objR.ColumnWidth
End Sub
また。このサンプルような単純な例では、「Withステートメント」を使ってオブジェクトの参照をまとめてしまうこともできます。
Sub TEST3()
    With Range("A1")
        MsgBox .Value & vbCr & _
               .Address & vbCr & _
               .Row & vbCr & _
               .Column & vbCr & _
               .RowHeight & vbCr & _
               .ColumnWidth
    End With
End Sub
単にピリオドから記述を始めるメソッドやプロパティは、直前の「Withステートメント」のメソッドやプロパティとして処理されます。
※ただし、「Withステートメント」で記述される「Withブロック」で指定できる引数オブジェクトは1つだけです。
さて、これで「Range」の記述自体がオブジェクトを指しているのではなく、これが「Rangeオブジェクト」を返すプロパティだという理解は得られたと思いますが、「Rangeプロパティ」以外にも同様に「Rangeオブジェクト」を返すプロパティやメソッドが多種あるので、紹介しておきます。
まず、■「Cellsプロパティ」です。
これは自動記録では登場しませんが、R1C1参照形式のようにセルを座標として縦横ともに数字番地で扱う考え方でマクロを記述される場合には多用されるプロパティで、単一セルの「Rangeオブジェクト」取得に用いられます。
Sub TEST4()
    Dim objR As Range
    Set objR = Cells(1, 1)
    MsgBox objR.Value & vbCr & _
           objR.Address & vbCr & _
           objR.Row & vbCr & _
           objR.Column & vbCr & _
           objR.RowHeight & vbCr & _
           objR.ColumnWidth
End Sub
これは、上の「TEST2」プロシージャから、Setステートメントの記述のみ「Cellsプロパティ」に変更したもので、同じ結果が得られます。
Cellsプロパティ」のカッコ内の引数は定数でも変数でも良く、カンマの左が「行」、右が「カラム」でこの数値で絶対参照されたセルが「Rangeオブジェクト」取得されます。

Rangeプロパティ」から「Rangeオブジェクト」を取得する場合は、
Sub TEST5()
    Dim objR As Range
    Set objR = Range("A1:D5")
    objR.Value = "aaa"
End Sub
のように記述して動作させると、
複数セルに同時に値をセットする例
このように5行×4列の20セルに同時に値をセットできますが、位置や行列数を変数で扱うような場合は「Rangeプロパティ」のカッコ内引数に「Cellsプロパティ」を組み合わせて、セル範囲の左上と右下を指定する方法があります。
Sub TEST6()
    Dim objR As Range
    Set objR = Range(Cells(1, 1), Cells(5, 4))
    objR.Value = "aaa"
End Sub
■「Resizeプロパティ」
最初に何らかの方法で左上基点の「Rangeオブジェクト」を取得してある前提で、下方向と右方向に行列数を変更したセル範囲の「Rangeオブジェクト」を再取得するプロパティです。
上の「TEST5」「TEST6」プロシージャと同じ結果を得るなら、
Sub TEST7()
    Dim objR As Range
    Set objR = Range("A1").Resize(5, 4)
    objR.Value = "aaa"
End Sub
このように記述します。これでA1セル基点で縦5行横4列のセル範囲が取得できます。
元々、「Rangeプロパティ」は「Rangeオブジェクト」を返すのですが、「Resizeプロパティ」は「Rangeオブジェクト」を返します。ここでは1行で記述していますが、
Sub TEST8()
    Dim objR As Range, objR2 As Range
    Set objR = Range("A1")
    Set objR2 = objR.Resize(5, 4)
    objR2.Value = "aaa"
End Sub
このように、分けて記述することと同じです。
■「Offsetプロパティ」
セル範囲のサイズ変更が「Resizeプロパティ」なら、位置の変更が「Offsetプロパティ」です。
たとえば、
Sub TEST9()
    Dim objR As Range, objR2 As Range, objR3 As Range
    Set objR = Range("A1")
    Set objR2 = objR.Resize(5, 4)
    Set objR3 = objR2.Offset(1, 1)
    objR3.Value = "aaa"
End Sub
このように記述して動かすと、
Offsetプロパティで基点位置を変更する。
このような結果になり、値がセットされるセル範囲が下方向に1行、右方向に1列シフトされます。
最終的なセル範囲だけを取得すれば良い場合は、「Resizeプロパティ」同様に1行にまとめて記述させても良く、
Sub TEST10()
    Dim objR As Range
    Set objR = Range("A1").Resize(5, 4).Offset(1, 1)
    objR.Value = "aaa"
End Sub
このようにも記述できます。
また、先に基点位置を変更するように、
Sub TEST11()
    Dim objR As Range
    Set objR = Range("A1").Offset(1, 1).Resize(5, 4)
    objR.Value = "aaa"
End Sub
このように記述しても同じ結果になります。
■その他
Excelが認知している最終行を取得する。」で説明している「Endプロパティ」「SpecialCellsメソッド」も同様に「Rangeオブジェクト」を返すものなので、使い方についてもここで説明している内容を理解すれば簡単です。
(重複するので、ここでは説明しません。Excelが認知している最終行を取得する。」を参照して下さい。)
また、ここでの記述はシートやブックを明示せず、単に「Rangeオブジェクト」を取得しようとする記述なので、アクティブなシート上でしか処理が行なえない記述です。これに対してシートやブックを明示しての「Rangeオブジェクト」の取得や参照は次項「シートやブックを越えたRangeオブジェクト取得」を参照して下さい。