TL;DR —
Selectionはいまハイライトされているものを指すライブなポインター です。多くの場合それはRange— 1つまたは複数のセル — なので、ループしたり、 合計したり、書式設定したりできます。しかしSelectionは同じくらいたやすく グラフ、シェイプ、あるいはオブジェクトのグループにもなり、そうなるとFor Each c In SelectionやSelection.Valueのようなコードは実行時エラーを 投げます。プロの習慣は2段構えです:セルに触れる前にTypeName(Selection) = "Range"でガードすること、そしてユーザー主導のツールで ないものにはSelectionをまったく使わず、意図する範囲を名指しすることです。
Sub SumTheSelection()
' まずガード:Selection はつねに範囲とは限らない
If TypeName(Selection) <> "Range" Then
MsgBox "Select some cells first.", vbExclamation
Exit Sub
End If
Dim cell As Range, total As Double
For Each cell In Selection.Cells
If IsNumeric(cell.Value) Then total = total + cell.Value
Next cell
MsgBox "Sum of selection: " & total
End Sub
Selection は単純に感じられます — 「ハイライトしたもの」ですから — そして、ユーザーが
選んだものに作用する手早いツールには、まさにうってつけです。問題が始まるのは、コードが
選択範囲をきれいなセルのブロックだと決めてかかるときです。そうでないことは多く、
しかも失敗は間違った答えではなく、いきなりのクラッシュです。この記事は、Selection が
本当は何になりうるのかを知り、それぞれのケースを扱うことについてです。
この記事で学べること
- 考え方の軸 — 名前を付けた範囲ではなく、ハイライトを指すライブなポインター
- それを役立てるルール — ふつうはループできる範囲
- コードをクラッシュさせるルール —
Selectionはつねに範囲とは限らない SelectionとActiveCell— ハイライト全体対、唯一のアンカー- 複数エリア選択 — Ctrl クリックによる
.Areasの罠 - より大きな教訓 — 非対話的なコードでは範囲を明示的に参照する
考え方の軸:ハイライトを指すライブなポインター
ActiveCell と同じく、Selection には固定の
アイデンティティがありません。それは、あなたが宣言したセルや範囲ではなく —
「いまアクティブウィンドウで何がハイライトされているか」という問いへの Excel の
答えです。別のセルをクリックすれば Selection は別のものを意味します。月曜に列を
ハイライトして、火曜にグラフを選択してマクロを走らせれば、Selection はある日は
Range、翌日は Chart です。
それが Selection をツールにとって強力にし — 「選んだものを書式設定する」ボタンは
まさにこれを必要とします — そして自動化にとって危険にします。ハイライトは、ユーザーが
たまたま残していったものだからです。Selection について知るべき最も重要なことは、
その型をあなたが制御できないということです。
それを役立てるルール:ふつうはループできる範囲
選択範囲がセルであるとき、Selection は Range で、あらゆる範囲のテクニックが
使えます。最もよくあるパターンは、選択セルのループです。
Sub HighlightNegatives()
Dim cell As Range
For Each cell In Selection.Cells
If IsNumeric(cell.Value) Then
If cell.Value < 0 Then cell.Interior.Color = vbRed
End If
Next cell
End Sub
選択範囲が範囲であるときに役立つメンバー:
Selection.Cells.Count— いくつのセルがハイライトされているかSelection.Rows.Count/Selection.Columns.Count— その形Selection.Address— ハイライトされたアドレス、例えば$B$2:$D$10Selection.Value— ただし単一セルのときだけ意味を持ちます。複数セルの選択では 2次元配列を返し、x = Selection.Valueをスカラーに代入すると先頭セルだけになるか エラーになります
最後の点は目立たないものです:Selection.Value は、多くの初心者が期待するようには、
ブロックの「合計」や「値」を返してくれません。複数セルの選択にわたって作業する
には、(上のように)ループするか、配列に読み込みます。
コードをクラッシュさせるルール:Selection はつねに Range とは限らない
これがナンバーワンの Selection バグです。あなたのマクロは選択範囲をループし、
何週間も完璧に動き、それからユーザーがグラフをクリックした状態で走らせると、
「オブジェクトはこのプロパティまたはメソッドをサポートしていません」(エラー 438)
または **「オブジェクトが必要です」(エラー 424)**で死にます。壊れたものは何も
ありません — 選択範囲が単に範囲ではないのです。
' クリックされたものによって、Selection がなりうるもの:
' セル -> Range
' グラフオブジェクト -> ChartObject / Chart
' シェイプ -> Shape
' 複数のオブジェクト -> DrawingObjects
' 使えるものが何もない -> 文脈による
直し方は、セルを前提とするマクロの先頭に置く1行のガードです — 触れる前に型を確認 します。
Sub NeedsCells()
If TypeName(Selection) <> "Range" Then
MsgBox "This tool works on cells. Select a range first.", vbExclamation
Exit Sub
End If
' ...ここから先は Selection を Range として安全に扱える...
End Sub
TypeName(Selection) は、セルがハイライトされているとき文字列 "Range" を返し、
それ以外では "ChartObject"、"Rectangle"、"Picture" などを返します。この
ガードを、選択ベースのツールでは反射にすること — それが、親切なメッセージと、
ユーザーの目の前でのクラッシュとの分かれ目です。
Selection と ActiveCell:ハイライト全体対、唯一のアンカー
この2つはたえず混同されるので、区別をはっきりさせておきましょう。
Selection |
ActiveCell |
|
|---|---|---|
| 範囲 | ハイライト全体 | 1つのアンカーセル |
| 数 | 1つまたは複数のセル(あるいはセル以外のオブジェクト) | つねにちょうど1つのセル |
| つねに範囲? | いいえ — シェイプ/グラフのこともある | セルのみ(グラフシートではエラー) |
.Value の読み取り |
複数セルでは配列 | つねに単一の値 |
| 使いどころ | 「ユーザーが選んだすべて」 | 「フォーカスされた1つのセル」 |
この2つは連携します:ActiveCell は Selection の内側のアンカーです。この対の
単一セル側については VBA ActiveCell を参照してください。
複数エリアの罠:Ctrl クリックが複数の Areas を作る
Selection が範囲であるときでさえ、もっと微妙な形の問題があります。ユーザーが
Ctrl クリックで A1:A5 と C1:C5 をハイライトすると、それは2つのエリアから
なる1つの選択範囲です。Selection.Cells に対する単一のループは、それでもすべての
セルを訪れます — しかし「その範囲」(そのアドレス、その角、Selection.Rows.Count)に
ついて推論するコードは、間違った答えを得かねません。それらは先頭エリアだけに
適用されるからです。
Sub WalkAllAreas()
Dim area As Range, cell As Range
Debug.Print "Areas selected: " & Selection.Areas.Count ' 例えば 2
For Each area In Selection.Areas
For Each cell In area.Cells
' ...各エリアの各セルを処理...
Next cell
Next area
End Sub
ルール:選択範囲が不連続かもしれないときは、Selection だけでなく
Selection.Areas をループする。 これは、上の非範囲のケースと同じ種類の「形が
思い込みと違う」バグです。
より大きな教訓:非対話的なコードでは範囲を名指しする
ここまではすべて Selection を安全に扱うことについてでした — しかしより深い教訓は、
いつそれを避けるべきかを知ることです。Selection は UI の状態に完全に依存し、
あなたの下で変化し、マクロが無人で走るときには何の意味も持ちません。ですから:
Selectionを使うのは、本当に対話的なツール — リボンのボタン、右クリックの 補助、「選んだものを書式設定する」マクロ — のときだけ。そこでは「ユーザーが ハイライトしたもの」が入力そのものです。Selectionを使わないのは、既知のデータを狙う自動化のとき。範囲を直接参照し —Worksheets("Data").Range("A1:A100")— マクロがカーソルの位置に依存しないように します。
これは、作用する前にセルを選択しないという、 VBA Select vs Activate で扱うのと同じ原則です: ライブな選択範囲に依存するマクロが少ないほど、ユーザーが予期しない場所をクリックした ときに壊れるものも少なくなります。
ExcelMaster の活用
Selection の罠 — セルの代わりのグラフ、複数エリアに分かれる Ctrl クリック、意図した
値ではない Selection.Value — は、どれも問題なくコンパイルされ、実行時に、しかも
誰か他の人のクリックで初めて噛みついてきます。ガードやエリアループを手で書くのは
面倒で、忘れやすいものです。
ExcelMaster
なら、代わりにツールを説明できます。「選択したセルを何でも合計するボタン」と頼めば、
TypeName ガードとエリア対応のループを書いてくれます。「Data シートの A 列を
きれいにして」と頼めば、Selection をまったく使わず、範囲を直接参照します。選択範囲が
どんな形で驚かせてくるかを一つひとつ覚えておかなくても、読みやすいマクロを保てます。
よくある質問
VBA で選択セルをループするには?
For Each cell In Selection.Cells を使います。例えば
For Each cell In Selection.Cells: Debug.Print cell.Address: Next cell。まず
If TypeName(Selection) <> "Range" Then Exit Sub でガードしてください。非範囲の
選択範囲(グラフなど)に対するループはエラーになるからです。Ctrl クリックの選択には、
Selection.Areas をループし、次に各エリアのセルをループします。
Selection のコードがエラー 438 や 424 を出すのはなぜですか?
そのとき Selection が Range ではないからです — セルではなくグラフ、シェイプ、
その他のオブジェクトが選択されていて、.Cells や .Value のような範囲のメンバーを
サポートしないのです。マクロの先頭に If TypeName(Selection) <> "Range" Then Exit Sub
を足せば、クラッシュせずにきれいに抜けます(あるいはユーザーに促します)。
Selection と ActiveCell の違いは何ですか?
Selection はハイライトされた領域全体で、多数のセル — あるいはシェイプやグラフさえ —
になりえます。ActiveCell はつねに、その選択範囲の内側にある唯一のアンカーセルです。
フォーカスされた1つのセルには ActiveCell、ユーザーがハイライトしたすべてが必要な
ときには Selection を使います。
選択セルの数を取得するには?
セルの総数には Selection.Cells.Count、その形には Selection.Rows.Count と
Selection.Columns.Count、そして単一のブロックか複数エリアの Ctrl クリックかを見る
には Selection.Areas.Count を使います。選択範囲が不連続のとき、行数・列数は先頭エリア
だけを表すことを覚えておいてください。
Selection を使うべきですか、それとも範囲を直接参照すべきですか?
Selection は、「ユーザーが選んだもの」に作用する対話的なツールのときだけ使います。
既知のデータを狙う自動化では、範囲を明示的に参照し — 例えば
Worksheets("Data").Range("A1:A100") — マクロがカーソルの位置に依存せず、間違った
セルに作用できないようにします。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-03。
関連ガイド: VBA ActiveCell · VBA Select vs Activate · VBA Range · VBA For Each · VBA Worksheet_SelectionChange
