VBA技術解説
RangeオブジェクトのFor EachとAreasについて

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
最終更新日:2021-04-08

RangeオブジェクトのFor EachとAreasについて


マクロ VBA Range Areas For Each


【VBA問題】
?Range("A1:B3,C2:E5").Columns.Count
さて結果は?

  • 2
  • 3
  • 5
  • にゃんともいえない


ツイッターでこのような出題をしました。
この出題にたいする解説記事になります。



正解は

2

RangeオブジェクトにはAreasがあります。
1つの矩形範囲が1つのArea(というのは無いが説明の便宜上)で、これが複数集まってAreasを形成しています。

Range("A1:B3,C2:E5")
この範囲は、以下の画像の選択範囲になります。

マクロ VBA Range Areas For Each

A1:B3
C2:E5
これらの1つ1つの範囲がAreaであり、2つのArea(Areas)でRangeオブジェクトが形成させています。

そこで、
Rangeオブジェクト.Columns.Count
これがなぜ2になるのかというと、既にお分かりだとは思いますが、
先の記述では、
Rangeオブジェクト.Areas(1)
このAreas(1)が省略されていることになります。

Areas(1)が"A1:B3"、Areas(2)が"C2:E5"になります。
つまり、
?Range("A1:B3,C2:E5").Areas(1).Columns.Count → 2
?Range("A1:B3,C2:E5").Areas(2).Columns.Count → 3


RangeオブジェクトをFor Eachで取得すると

Range("A1:B3,C2:E5")
このRangeオブジェクトをFor Eachで処理した場合にどうなるでしょうか。


Range("A1:B3,C2:E5")

Dim myRng As Range, rng As Range
Set myRng = Range("A1:B3,C2:E5")
For Each rng In myRng
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

RangeのFor Eachでは、Areasの順に、その中で先に横方向に動きます。
そして、結果は予想通りに指定された範囲のセルが順に処理されていますね。

.Cellsを付けて全体を指定しても同じことになります。



For Each rng In myRng.Cells
  Debug.Print rng.Address(False, False)
Next

Cellsプロパティは、Rangeオブジェクトの全体なので、上のmyRngだけ指定した場合と同様になります。

以下、For Eachの部分のコードのみ掲載します。


Range("A1:B3,C2:E5").Rows

For Each rng In myRng.Rows
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

"A1:B3,C2:E5"この2つの範囲を順に行単位で取得しています。


Range("A1:B3,C2:E5").Columns

For Each rng In myRng.Columns
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

"A1:B3,C2:E5"この2つの範囲を順に列単位で取得しています。


Range("A1:B3,C2:E5").Areas



For Each rng In myRng.Areas
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Areas(1),Areas(2)の順に取得しています。


RangeオブジェクトをItemで取得すると

Range("A1:B3,C2:E5")
このRangeオブジェクトを1~CountまでItemで処理した場合にどうなるでしょうか。


Range("A1:B3,C2:E5").Item(i)

Dim myRng As Range, rng As Range, i As Long
Set myRng = Range("A1:B3,C2:E5")
For i = 1 To myRng.Count
  Debug.Print myRng.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

何やらおかしいですね。
"A1:B9"の範囲が取得されています。
myRng.Item(i)
これは、Areas(1)が省略されている状態で、
myRng.Areas(1).Item(i)
つまり、
"A1:B3"
このRangeオブジェクトの範囲が拡張されてしまっています。
RangeのItemでは、その範囲を超えてもエラーにならずに、範囲が縦に拡張されて取得されます。
(もちろん、シート範囲を超えてしまう場合はエラーになります。)


Range("A1:B3,C2:E5").Columns.Item(i)

最初の問題のように、
myRng.Columns.Count
これは2になってしまうので、以下では1~5で実行しました。

For i = 1 To 5
  Debug.Print myRng.Columns.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

やはりおかしいですね。
myRng.Columns.Item(i)
これは、Areas(1)が省略された状態になってしまいます。
myRng.Areas(1).Columns.Item(i)
つまり、
Areas(1)である"A1:B3"
このRangeオブジェクトの範囲が(Columnsなので横に)拡張されてしまっています。

"C2:E5"はAreas(2)になるので、
myRng.Areas(2).Columns.Item(i)
このように取得する必要があります。

したがって、Areasが複数ある場合にColumnsを使うなら、AreasをFor Eachで処理して、そのループの中でColumnsを使うと良いでしょう。


Range("A1:B3,C2:E5").Rows.Item(i)

myRng.Rows.Count
これは3になってしまうので、以下では1~5で実行しました。

For i = 1 To 5
  Debug.Print myRng.Rows.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Columns同様におかしいですね。
myRng.Rows.Item(i)
これは、Areas(1)が省略された状態になってしまいます。
myRng.Areas(1).Rows.Item(i)
つまり、
Areas(1)である"A1:B3"
このRangeオブジェクトの範囲が(Rowsなので縦に)拡張されてしまっています。


Range("A1:B3,C2:E5").Areas.Item(i)

For i = 1 To myRng.Areas.Count
  Debug.Print myRng.Areas.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Areasはインデックスの範囲を超えて指定することは出来ません。
今回の場合であれば、
myRng.Areas.Countの2を超えて3以上を指定した場合はエラーになります。

マクロ VBA Range Areas For Each


RangeオブジェクトのFor EachとAreasの最後に

Areasが複数あるRangeオブジェクトを扱うのは結構面倒な場合がでてきます。
頻繁に扱う事は無いと思いますが、
手動で範囲選択したRangeオブジェクトや、VBAでUnionしたRangeオブジェクトの場合はAreasに注意が必要になります。

そのような場合は、For EachでAreasを処理して、そのループの中に本来の処理を組み込むようにすると良いでしょう。




同じテーマ「マクロVBA技術解説」の記事

ユーザーに絶対に停止させたくない場合のVBA設定
列幅・行高をDPI取得しピクセルで指定する
VBAでWMIの使い方について
アクティブシート以外のWindowを設定できるWorksheetView
LSetとユーザー定義型のコピー(100桁の足し算)
省略可能なVariant引数の参照不可をラップ関数で利用
ブックのいろいろな開き方(GetObject,参照設定,アドイン)
入力規則への貼り付けを禁止する
Select Caseでの短絡評価(ショートサーキット)の使い方
RangeオブジェクトのFor EachとAreasについて
画像が行列削除についてこない場合の対処


新着記事NEW ・・・新着記事一覧を見る

VLOOKUPを使うことを基本としてシートを設計すべきか|エクセル雑感(2021-08-17)
コンピューターはブラックボックスで良い|エクセル雑感(2021-08-14)
小文字"abc"を大文字"ABC"に変換する方法|エクセル雑感(2021-08-13)
ADOでテキストデータを集計する|VBAサンプル集(2021-08-04)
VBA学習のお勧めコース|エクセル雑感(2021-08-01)
エクセル馬名ダービー|エクセル雑感(2021-07-21)
在庫を減らせ!毎日棚卸ししろ!|エクセル雑感(2021-07-05)
日付型と通貨型のValueとValue2について|エクセル雑感(2021-06-26)
DXってなんだ? ITと何が違うの?|エクセル雑感(2021-06-24)
エクセルVBA 段級位 目安|エクセル雑感(2021-06-21)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.Excelショートカットキー一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.RangeとCellsの使い方|VBA入門
5.繰り返し処理(For Next)|VBA入門
6.マクロって何?VBAって何?|VBA入門
7.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
8.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
9.セルに文字を入れるとは(Range,Value)|VBA入門
10.とにかく書いてみよう(Sub,End Sub)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ