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

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2021-04-08 最終更新日: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技術解説」の記事

ブックのいろいろな開き方(GetObject,参照設定,アドイン)
入力規則への貼り付けを禁止する
Select Caseでの短絡評価(ショートサーキット)の使い方
RangeオブジェクトのFor EachとAreasについて
画像が行列削除についてこない場合の対処
新関数SORTBYをVBAで利用するラップ関数を作成
LAMBDA以降の新関数はVBAで使えるか
数字(1~50)を丸付き数字に変換するVBA
文字列のプロパティ名でオブジェクトを操作する方法
OneDrive使用時のThisWorkbook.Pathの扱い方
セル個数を返すRange.CountLargeプロパティとは


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

ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
累計を求める数式あれこれ|エクセル関数応用(2024-01-22)
複数の文字列を検索して置換するSUBSTITUTE|エクセル入門(2024-01-03)
いくつかの数式の計算中にリソース不足になりました。|エクセル雑感(2023-12-28)
VBAでクリップボードへ文字列を送信・取得する3つの方法|VBA技術解説(2023-12-07)
難しい数式とは何か?|エクセル雑感(2023-12-07)


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

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.変数宣言のDimとデータ型|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.並べ替え(Sort)|VBA入門
8.条件分岐(IF)|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.マクロとは?VBAとは?VBAでできること|VBA入門




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


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



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