和風スパゲティのレシピ

日本語でコーディングするExcelVBA

RangeとCellsの違い

VBAでセルを指定する際に使用する、RangeとCellsの違いを解説します。

同じところ

どちらもセルを指定・取得するために使います。

Range("A1")
Cells(1, 1)

これはどちらも「A1セル」を取得します。

違うところ

Rangeの方ができることが多く、特に「セル範囲」や「複数のエリア」を取得できます。

以下はいずれも「A1からC3までの3×3の正方形」を取得します。

Range("A1:C3")
Range("A1","C3")
Range("A1:A3","C1:C3")
Range("A1:C1","A3:C3")
Range("正方形") ' セル範囲に「正方形」という名前をつけておいた場合

 
また、

Range("A1,B2,C3")

と指定すると、飛び飛びの3つのセルを指定することもできます。


他には、

Range("A:A")
Range("1:1")

という指定で、行全体や列全体を取得することもできます。

使い分け

↑の違いを見ると、

「じゃあ全部Rangeでいいじゃん!」

と思いそうになりますし、実際やろうと思えば全部Rangeでやることはできます。


ではCellsは何のためにあるかというと、セルの指定が「数値オンリー」でいけることを利用して、「変数や定数を使うため」に使います。


例えば、「A1からJ1までのセル」をループしたいとき、Cellsを使えば

Dim C As Long
For C = 1 To 10
    Cells(1, C) = ○○
Next

と書くことができますが、Rangeで同じことをするのは少々面倒です。


同じ様にA1からA10をループする場合は、

Dim R As Long
For R = 1 To 10
    Cells(R, 1) = ○○
    Range("A" & R) = ○○
Next

と、こちらはまだRangeでも、セルアドレスを文字列結合で作って何とかできますが、
書きやすさ(融通が利く編集ができるか)や、コードの再利用性などを考えると、
前者のCells(R, 1)を使用した方が良いでしょう。
(気にするレベルではないですが、速度もちょっぴり↑が早いです)


あとは、列番号B,C,Dを表の見出しを使った定数にしておくことで↓

Const 価格列 = 2
Const 個数列 = 3
Const 売上列 = 4

Cells(R, 4) = Cells(R, 2) * Cells(R, 3)
 ' ↓定数を使って書き替え 
Cells(R, 売上列) = Cells(R, 価格列) * Cells(R, 個数列)

このようにコードを書くことができます。

  • 改修が楽(Constの部分だけいじれば、1個ずつ書き換える必要がない)
  • コメントなしでも何をやっているかわかる

というのが主なメリットですが、この「列番号の定数化」にもCellsが必要になります。


このように、変数や定数を使用する場合は、Cellsを使ってください。


ちなみにCellsは単独のセルを指定することしかできませんが、
単独のセルならCellsを使うべきというわけではありません。

あくまで変数や定数と相性がいいというだけなので、
変数を使う必要のない、本当に固定の1セルであるならば、

Range("A1")

の方が、見やすくていいことも多いでしょう。この辺は好きに使い分けてください。


続いてRangeを使う場面ですが、Rangeさんは万能なので、
Cellsを使えないセルの指定すべてが役目みたいなものです。


特に重要な使いどころは、「セル範囲」の指定になります。


冒頭であった「A1からC3までの3×3の正方形」を取得する、

Range("A1:C3")

この使い方ですね。


この範囲指定には、Cellsとの合わせ技を使うことができ、

Range(Cells(1, 1), Cells(3, 3))

でも"A1:C3"を取ってくることができます。

もちろんこんな数字ベタ打ちで使う意味はあまりありませんので、
先ほどと同様、「セル範囲の取得にも変数・定数を使いたい」場面で使用してください。



最後に特殊な例として、

Cells

と()なしで書いた場合は、「シートのセルすべて」を指すことができます。

Rangeではこれができないため、セル範囲なのにCellsを使う唯一の例外です。
覚えておきましょう。

おまけ:その他のセル範囲指定方法

CellsとRangeの使い分けというとこの辺になりますが、
セルやセル範囲を指定する方法は、この2つだけではありません。


行や列を取得するRows,Columnsも便利ですし、
取得したセルやセル範囲を加工する、ResizeやOffsetも使いこなせると非常に便利な武器になります。


例えば今回の3×3正方形も、

Cells(1, 1).Resize(3, 3)

という指定をすることができると、
「行数」や「列数」といった変数も範囲指定に使えるようになります。

今までで1番、3×3の正方形っぽさが表現できてますからね。


表形式のデータを扱うExcelでは、表全体や、ある列、ある行などを指定する場面がたくさんあります。

Rangeでの範囲指定に慣れてきたら、
いろいろなセル範囲の指定方法を勉強してみるといいかもしれません。


よろしければこちらの記事もどうぞ
www.limecode.jp


おまけ:厳密な用語の定義

実務的な説明は以上になります。


一応ここは用語の違いを説明するカテゴリでもあるため、
ここから先は用語に関する補足説明を書いていきますね。

とりあえずマクロが動けばOK!な方は、ここから先は別に読む必要はありません。
結構難しい話なので、読んでみてわからなければすっ飛ばしてもOKです。



今回違いを比べた「Range()」と「Cells()」は、正式にはそれぞれ
Rangeプロパティ」「Cellsプロパティ」と呼びます。

本記事タイトルは、正確には「RangeプロパティとCellsプロパティの違い」です。


そして混乱を避けるためにあえて書いてきませんでしたが、
VBA上で操作する「セル」や「セル範囲」のことを、「Rangeオブジェクト」と呼びます。

これがすごく似ている名前なので、混乱しやすい部分なんですね。


ここまでをまとめると、

  • RangeプロパティはRangeオブジェクトを取得するプロパティ
  • CellsプロパティはRangeオブジェクトを取得するプロパティ

です。
 

Range("A1")

は、用語をちゃんと入れて書くと、
「Rangeプロパティの引数に"A1"を渡して取得した、
 RangeオブジェクトであるA1セル」
と表現します。


この説明が良くわからない方は、今はひとまず置いておいてください。
他のもっと簡単なオブジェクトを扱ううちに、なんとなくわかってくると思います。

Rangeオブジェクトは全オブジェクトの中でも、かなり難しい部類に入りますので、
ここから勉強しようと思わない方がいいです。


なので心の片隅にでもおいておいてください。


Rangeオブジェクト(セル)の機能を学ぶときに、
Rangeと聞いて今回のRangeプロパティが頭に浮かんでしまって、
訳が分からなくなる事態さえ回避できればOKです。



オブジェクトがなんとなくわかってきたから、
今回の話をちゃんと理解してみたい!という方は、
よろしければこちらの記事をどうぞ。

www.limecode.jp

さらに厳密には

さらに正確に書いておくと、今回の両プロパティは、「Worksheetオブジェクトのプロパティ」です。

上のすべての例では「ActiveSheet.」が省略されているだけで、
親はすべて「Worksheetオブジェクト」でした。


Rangeプロパティ、Cellsプロパティ共に、Worksheetオブジェクト以外のプロパティとして登場することもあり、その時は、上の例とは違う動きをします。


例えば両プロパティとも、Rangeオブジェクトのプロパティとしても存在し、

Range("B2").Range("B2")
Cells(2, 2).Cells(2, 2)

これはどちらも「C3」を指します。

RangeオブジェクトのRangeプロパティは、相対位置(親のRangeオブジェクトがA1だったとした時の場所)っぽいプロパティです。Offsetと似てますね。


RangeプロパティとCellsプロパティが2個ずつ出てきていますが、
前者はWorksheetオブジェクトの、後者はRangeオブジェクトのプロパティであるため、厳密には別物です。


他には、

Range("A1").ListObject.Range ' テーブルが設置されているセル範囲
ActiveSheet.AutoFilter.Range ' オートフィルターが設置されているセル範囲

など、「ある機能が設置されているセル範囲全体」を取得するプロパティにも、
Rangeと名付けられているものがありますね。



まあこんなこと、ぶっちゃけ実務では意識しなくてもいいんですけどね。

プロのプログラマがそれでお金をもらっているわけでもなければ、
とりあえず動いた時点で事務のマクロとしては満点だと思います。


ただ、この辺のオブジェクトの理解があると、

  • 何かが起こって原因を調べたいとき
  • 他のいろいろな機能を勉強するとき

に、事がスムーズに運びます。


VBAをがっつり勉強したい方は、「オブジェクト.プロパティ」という並びを意識して「.」を見るようにしてみてください。

なんとなく把握していた知識が、点が線になるきっかけになると思いますよ。

さらにさらに厳密には

Worksheets("Sheet2").Range("A1")
Range("Sheet2!A1")

これはどっちも「Sheet2」のA1セルを取得します。
ActiveSheetがSheet1だったとしても関係ないです。


ということで、「Rangeの親を省略時はActiveSheet.が~~」は厳密には嘘です。



これはどういうことかというと、


と、もうやめておきますね(笑)



Rangeオブジェクトは、VBAの主人公と見せかけて、たぶんラスボスです。

今日見かけたRangeは、最初の町から見えるけど、すぐにはいけない魔王城です。


VBAの最後のカギを手に入れたという自信がついたら、こんな「実務なんだから母国語でやれや」って投げやりなサイトでなく、英語で書かれた専門書を読んで勉強してください。

私は最後のカギを持っていませんのであしからず。