和風スパゲティのレシピ

日本語でコーディングする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正方形も、セル範囲を拡大縮小するResizeを使用して、

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"を渡して取得した、
 A1セルというRangeオブジェクト」
と表現できます。


さて、ここで「オブジェクト」と「プロパティ」という用語が出てきました。

この二つはプログラミングにおいて超重要なもので、
かなり奥が深いため一言で説明するのは難しいのですが、
ざっくりいうと、

オブジェクトという人がいて、その人の持ち物を見に行くのがプロパティ

みたいなものと思っておいてください。

Range("A1").Value

は、「A1セルの値」を見に行っていますが、これを正確な用語で書くと、
Rangeオブジェクト(A1セル)のValueプロパティを取得する」と表現します。

「A1セル」さんの持ち物のひとつである「値」を、
Valueプロパティで見に行ったとイメージしてください。


さて、これでRangeオブジェクトはなんとなくわかったと思いますが、
今回のRange、CellsをなぜRange「プロパティ」と呼ぶのでしょうか?


誰かの持ち物を見に行っているということですよね?


この答えは単純で、今回の両プロパティは、
Worksheetオブジェクトのプロパティ」ということです。

「セル」は、親である「ワークシート」の持ち物みたいなものですからね。


今回紹介したすべての例では「ActiveSheet.」が省略されている扱いで、
親はすべて「Worksheetオブジェクト」となります。


Worksheetオブジェクトの持ち物であるセルを見に行くための道具として、
RangeプロパティやCellsプロパティがあるということです。


かなりざっくりとした説明でしたが、なんとなくわかりましたでしょうか?

この辺の話はかなり難しいので、とりあえずマクロを動かすのを優先して、
理解するのは後回しにしてもいいと思います。


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

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

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


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

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


興味がある方は、まずはこの記事を読んでみてください。

www.limecode.jp

Worksheet以外を親に持つRangeプロパティについて

一応補足しておきますと、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と名付けられているものがあります。

↑はListObject家のたかしさんで、↓はAutoFilter家のたかしさんですので、
これらも全く別のプロパティです。


オブジェクトとプロパティの関係を理解しきれていないと、混乱すると思いますが、そんな厳密にとらえなくても、なんとなく知っておくだけでも十分だと思います。

まあなんかいろいろなRangeさんがいるんだな~と思っておいてください。