🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Selection — ハイライトされたものを扱う(そして、なぜつねに Range とは限らないのか)

|

Excel VBA の Selection — ハイライトされたものを扱う(そして、なぜつねに Range とは限らないのか)

TL;DRSelectionいまハイライトされているものを指すライブなポインター です。多くの場合それは Range — 1つまたは複数のセル — なので、ループしたり、 合計したり、書式設定したりできます。しかし Selection は同じくらいたやすく グラフ、シェイプ、あるいはオブジェクトのグループにもなり、そうなると For Each c In SelectionSelection.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 はつねに範囲とは限らない
  • SelectionActiveCell — ハイライト全体対、唯一のアンカー
  • 複数エリア選択 — Ctrl クリックによる .Areas の罠
  • より大きな教訓 — 非対話的なコードでは範囲を明示的に参照する

考え方の軸:ハイライトを指すライブなポインター

ActiveCell と同じく、Selection には固定の アイデンティティがありません。それは、あなたが宣言したセルや範囲ではなく — 「いまアクティブウィンドウで何がハイライトされているか」という問いへの Excel の 答えです。別のセルをクリックすれば Selection は別のものを意味します。月曜に列を ハイライトして、火曜にグラフを選択してマクロを走らせれば、Selection はある日は Range、翌日は Chart です。

それが Selectionツールにとって強力にし — 「選んだものを書式設定する」ボタンは まさにこれを必要とします — そして自動化にとって危険にします。ハイライトは、ユーザーが たまたま残していったものだからです。Selection について知るべき最も重要なことは、 その型をあなたが制御できないということです。

それを役立てるルール:ふつうはループできる範囲

選択範囲がセルであるとき、SelectionRange で、あらゆる範囲のテクニックが 使えます。最もよくあるパターンは、選択セルのループです。

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$10
  • Selection.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つは連携します:ActiveCellSelection内側のアンカーです。この対の 単一セル側については 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 を出すのはなぜですか?

そのとき SelectionRange ではないからです — セルではなくグラフ、シェイプ、 その他のオブジェクトが選択されていて、.Cells.Value のような範囲のメンバーを サポートしないのです。マクロの先頭に If TypeName(Selection) <> "Range" Then Exit Sub を足せば、クラッシュせずにきれいに抜けます(あるいはユーザーに促します)。

Selection と ActiveCell の違いは何ですか?

Selection はハイライトされた領域全体で、多数のセル — あるいはシェイプやグラフさえ — になりえます。ActiveCell はつねに、その選択範囲の内側にある唯一のアンカーセルです。 フォーカスされた1つのセルには ActiveCell、ユーザーがハイライトしたすべてが必要な ときには Selection を使います。

選択セルの数を取得するには?

セルの総数には Selection.Cells.Count、その形には Selection.Rows.CountSelection.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