Excel VBAを直接操作・機能呼出し・UI操作の三層で理解する

記事155 | Excel VBAを直接操作・機能呼出し・UI操作の三層

LWP ARTICLE · EXCEL & BUSINESS DESIGN

Excel VBAを直接操作・機能呼出し・UI操作の三層で理解する

~Selectを消すだけで終わらず、データ処理と画面案内の境界を設計する~

Copyright © 2026 LWP 山中 一弘

本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。

記事要約

Excel VBAには、同じ結果へ到達するように見えても、実行時の安定性が大きく異なる書き方があります。対象のWorkbook、Worksheet、Rangeを明示して直接操作するコードと、ActiveSheetやSelectionなど現在の画面状態を使うコードです。

ただし、単純に「Selectは悪い、直接指定は正しい」と覚えるだけでは不十分です。Excelのフィルターや並べ替えをRangeから呼ぶ処理は、画面機能に対応していてもUI操作そのものではありません。一方、処理結果を利用者へ見せるためのActivateやGotoは、画面状態を変えること自体が目的です。

この記事では、VBAを「データ・オブジェクトの直接操作」「Excel機能の呼び出し」「UI状態の操作」の三層に分けます。処理本体は上の二層で作り、UI操作は入口と出口に限定する、という設計原則まで落とし込みます。

判断の核:SelectやActivateの有無だけで善悪を決めず、その行の目的が「データを変えること」か「人が見る画面を変えること」かで判断します。

本記事の対象とゴール

想定読者

  • マクロ記録からVBAを学び始めた人

  • ActiveSheetやSelectionに依存する既存マクロを読み解きたい人

  • データ処理と画面操作を分離したい開発者

  • AIへVBA生成を依頼する際の品質基準を持ちたい人

本記事で得られること

  1. 同じExcelオブジェクトモデルに、性格の異なる操作が混在する理由を説明できます。

  2. AutoFilterやSortを、UI模倣ではなくExcel機能呼び出しとして整理できます。

  3. 暗黙の対象を明示し、実行状態に左右されにくいコードへ直せます。

  4. UI操作を禁止するのではなく、必要な場所へ閉じ込められます。

1. 同じ結果でも、依存している状態が違う

次の二つのコードは、どちらも売上シートのA1へ100を設定する意図で書かれています。

ThisWorkbook.Worksheets("売上").Range("A1").Value = 100

Worksheets("売上").Activate
Range("A1").Select
Selection.Value = 100

一つ目は、処理対象がコード内で確定しています。二つ目は、シートをアクティブにし、セルを選択し、現在の選択へ値を入れます。途中で別のコードやイベントが選択状態を変えれば、結果も変わる可能性があります。

違いは行数だけではありません。コードが必要とする「実行時の文脈」が違います。

  • 明示的な文脈:Workbook変数、Worksheet変数、Range変数

  • 暗黙の文脈:ActiveWorkbook、ActiveSheet、ActiveCell、Selection

大きな業務マクロほど、暗黙の文脈を減らした方が、処理対象を追いやすくなります。

2. 二分類から三層モデルへ進む

「直接操作」と「UI操作」の二分類は入口として便利です。しかし、AutoFilter、Sort、RemoveDuplicates、PivotTableなどをどちらへ置くかで迷います。そこで三層に分けます。

第1層:データ・オブジェクトの直接操作

セル値、数式、配列、書式、オブジェクトの属性を直接読み書きします。

targetRange.Value = sourceArray
targetRange.ClearContents
targetRange.NumberFormatLocal = "yyyy/mm/dd"

処理対象と到達させたい状態が中心です。画面で何が選択されているかは、本来関係ありません。

第2層:Excel機能の呼び出し

フィルター、並べ替え、重複削除、計算、ピボット更新など、Excelが持つ機能をオブジェクトから呼びます。

dataRange.AutoFilter Field:=3, Criteria1:="東京"
dataRange.Sort Key1:=dataRange.Columns(2), Order1:=xlAscending, Header:=xlYes
dataRange.RemoveDuplicates Columns:=Array(1, 2), Header:=xlYes

これらは画面上ではリボン操作に対応しますが、コードがボタンをクリックしているわけではありません。Rangeなどのオブジェクトへメソッドを実行しています。

第3層:UI状態の操作

利用者が何を見るか、どこを選ぶか、どの倍率で表示するかを変えます。

outputSheet.Activate
Application.Goto outputSheet.Range("A1"), True
ActiveWindow.Zoom = 90

この層では、画面状態の変更そのものが成果です。データ処理から排除するのではなく、役割を限定して使います。

3. オブジェクト階層をたどると対象が確定する

Excelは、概念的に次の階層を持っています。

Application
└ Workbook
└ Worksheet
└ Range
├ Value
├ Formula
├ AutoFilter
└ Sort

次のコードは、この階層を明示的にたどっています。

Dim wb As Workbook
Dim ws As Worksheet
Dim targetRange As Range

Set wb = ThisWorkbook
Set ws = wb.Worksheets("売上")
Set targetRange = ws.Range("A1:D100")

以後はtargetRangeを使えば、利用者が別シートを表示していても対象は変わりません。変数は単なる省略記法ではなく、「どのブックの、どのシートの、どの範囲か」を固定する契約です。

4. 修飾なしのRangeが隠しているもの

標準モジュールで次のように書くと、Rangeの親シートがコードに現れません。

Range("A1").Value = 100

通常はアクティブなシートが文脈になります。コードの直前で目的のシートをActivateしていれば動きますが、処理の途中で別シートがアクティブになると対象も変わります。

次のように親を明示すれば、画面状態から切り離せます。

ws.Range("A1").Value = 100

CellsをRangeの内側で使う場合も同じ親で修飾します。

With ws
Set targetRange = .Range(.Cells(2, 1), .Cells(lastRow, 4))
End With

ドットのないCellsが混ざると、Rangeはwsを見ているのにCellsはActiveSheetを見る、という事故が起こり得ます。

5. Selectionはセルとは限らない

MicrosoftのVBAリファレンスでは、Application.Selectionはアクティブなワークシートで現在選択されているオブジェクトを返します。選択対象によって型が変わり、Rangeだけでなく図形やグラフになることがあります。

したがって、選択範囲を入力として受け取るツールでは、型と範囲を検証します。

Public Sub 選択セルを強調する()

If TypeName(Application.Selection) <> "Range" Then
MsgBox "セル範囲を選択してから実行してください。", vbExclamation
Exit Sub
End If

Dim targetRange As Range
Set targetRange = Application.Selection

If targetRange.Areas.Count > 1 Then
MsgBox "連続した一つの範囲を選択してください。", vbExclamation
Exit Sub
End If

targetRange.Font.Bold = True

End Sub

ここではSelectionの使用が誤りなのではありません。「利用者が選んだ範囲」が正式な入力だからです。問題は、入力条件を検査せず、Selectionを常にRangeだと思い込むことです。

6. AutoFilterはUI操作ではない

マクロ記録では、AutoFilterが次のように記録されることがあります。

Range("A1:D100").Select
Selection.AutoFilter Field:=3, Criteria1:="東京"

しかし、フィルターをかけるために範囲を画面上で選ぶ必要はありません。

Dim dataRange As Range
Set dataRange = ThisWorkbook.Worksheets("売上").Range("A1:D100")

dataRange.AutoFilter Field:=3, Criteria1:="東京"

このコードは、Rangeオブジェクトが公開しているAutoFilterメソッドを呼んでいます。フィルター矢印が画面に現れるためUI的に見えますが、処理の本体は第2層のExcel機能呼び出しです。

判断するときは、「Excel画面にも同じ機能があるか」ではなく、「現在の選択状態を処理対象の決定に使っているか」を見ます。

7. マクロ記録は完成品ではなく調査装置

マクロ記録は、利用者が行った操作を再現しようとします。目的を理解して、最小のオブジェクト操作へ変換する機能ではありません。そのため、Select、Selection、Activateが多く含まれます。

それでもマクロ記録は有用です。特に、条件付き書式、グラフ、印刷設定、ピボットなど、メソッド名や引数が分からない機能を調べる手掛かりになります。

使い方は次の順です。

  1. 記録を開始し、目的の操作だけを行う

  2. 生成コードから対象オブジェクト、メソッド、引数を探す

  3. SelectとActivateを外して、対象変数からメソッドを呼ぶ

  4. 固定アドレス、既定値、不要な書式指定を整理する

  5. 別シートを表示した状態でも同じ結果になるか試す

記録コードを捨てるのではなく、Excelオブジェクトモデルを調べるプローブとして利用します。

速度改善は副次効果として扱う

SelectやActivateを減らすと、画面の切り替えや再描画が減り、結果として速くなることがあります。しかし、直接操作へ直す第一の目的は、速度ではなく処理対象を固定することです。データ量、計算式、イベント、ブック構造によっては、Selectを外しただけでは体感速度がほとんど変わらない場合もあります。

Application.ScreenUpdating = Falseを使えば画面のちらつきは抑えられますが、ActiveSheetやSelectionへの依存は消えません。また、処理途中でエラーになると画面更新が無効のまま残る危険があります。高速化を行う場合も、まず対象オブジェクトを明示し、その後で計測し、画面更新・イベント・計算モードを変更した場合は必ず元へ戻します。

8. コピーは目的に応じて抽象度を選ぶ

マクロ記録に近い書き方は、選択とクリップボードを経由します。

sourceRange.Select
Selection.Copy
destinationRange.Select
ActiveSheet.Paste

書式や数式も含めてコピーしたいなら、対象を明示したCopyを使えます。

sourceRange.Copy Destination:=destinationRange

値だけを移したいなら、クリップボードを使わず代入できます。

destinationRange.Value = sourceRange.Value

最短のコードを選ぶのではなく、何を複製するのかを先に決めます。値だけ、数式、書式、列幅まで含むコピーは、それぞれ異なる処理です。

9. データ処理と画面案内を別の手続きにする

処理本体の最後へ無造作にActivateを混ぜると、テストや再利用が難しくなります。データ処理と、結果を見せる処理を分けます。

Public Function 売上抽出(ByVal sourceSheet As Worksheet, _
ByVal outputSheet As Worksheet, _
ByRef resultMessage As String) As Boolean

On Error GoTo ErrorHandler

Dim dataRange As Range
Set dataRange = sourceSheet.Range("A1").CurrentRegion

outputSheet.Range("A2:D" & outputSheet.Rows.Count).ClearContents
dataRange.AutoFilter Field:=3, Criteria1:="東京"

Dim visibleRange As Range
On Error Resume Next
Set visibleRange = dataRange.Offset(1).Resize(dataRange.Rows.Count - 1) _
.SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler

If visibleRange Is Nothing Then
resultMessage = "該当データはありません。"
売上抽出 = True
Exit Function
End If

visibleRange.Copy Destination:=outputSheet.Range("A2")
resultMessage = "売上データを抽出しました。"
売上抽出 = True
Exit Function

ErrorHandler:
売上抽出 = False
resultMessage = "売上抽出に失敗しました:" & Err.Description

End Function

画面案内は、成功した後に入口側で行います。

Public Sub 売上抽出を実行する()

Dim sourceSheet As Worksheet
Dim outputSheet As Worksheet

Set sourceSheet = ThisWorkbook.Worksheets("売上")
Set outputSheet = ThisWorkbook.Worksheets("出力")

Dim resultMessage As String

If 売上抽出(sourceSheet, outputSheet, resultMessage) Then
outputSheet.Activate
Application.Goto outputSheet.Range("A1"), True
MsgBox resultMessage, vbInformation
Else
MsgBox resultMessage, vbExclamation
End If

End Sub

これなら、処理本体は画面を切り替えず、メッセージボックスも表示せずに検証できます。処理結果は戻り値とメッセージ文字列で入口へ返し、入口だけが利用者へ結果を見せます。

10. UI操作を使うべき場面

UI状態の操作には、正当な用途があります。

  • 処理後に結果シートを表示する

  • 入力漏れのセルへ移動する

  • 利用者が選んだ範囲を正式な入力として受け取る

  • ズームやスクロール位置を整えて帳票を見せる

  • アドインや開発支援ツールで、現在の選択を調査する

このときも、UI操作を一か所へまとめ、実行前提を明示します。たとえば、選択対象の型、アクティブなブック、保護状態、複数範囲の可否を確認します。

11. 既存コードを直すときの順序

Selectを機械的に一括削除すると、必要なUI操作まで壊したり、修飾先を誤ったりします。次の順で直します。

  1. マクロの入力、出力、最終的に見せる画面を確認する

  2. ActiveWorkbookとThisWorkbookのどちらが正しいか決める

  3. Workbook、Worksheet、Rangeを変数へ固定する

  4. Select/Selectionの組を、対象オブジェクトの直接呼び出しへ置き換える

  5. コピーの目的が値、数式、書式のどれかを確認する

  6. 画面案内として必要なActivate/Gotoだけを出口へ残す

  7. 別ブック・別シートを表示した状態で再テストする

修正のゴールはSelectを0件にすることではありません。処理対象が意図どおりに決まり、必要なUI操作だけが目的を持って残っていることです。

12. AIへVBA生成を依頼するときの指示

AIには、次のように条件を渡すと安定します。

データ処理では、Workbook・Worksheet・Rangeの親を明示する。
ActiveWorkbook、ActiveSheet、Selection、ActiveCellへ依存しない。
Excel機能は、対象RangeやWorksheetから直接呼び出す。
結果画面の表示だけは、処理成功後にUI案内手続きで行う。
利用者の選択を入力にする場合は、Selectionの型と範囲を検証する。

さらに、別シートを表示した状態、図形を選択した状態、対象データ0件の状態をテスト条件として渡すと、暗黙の状態依存を見つけやすくなります。

13. まとめ

Excel VBAは、セルや配列を操作するプログラミング環境であると同時に、Excelという対話型アプリケーションを制御する仕組みです。この二面性があるため、データ処理と画面操作が同じコードへ混ざりやすくなります。

整理すると、実務で使う操作は三層です。

  1. データ・オブジェクトを直接操作する

  2. Excel機能を対象オブジェクトから呼び出す

  3. 利用者が見るUI状態を操作する

処理本体は第1層と第2層を中心に作り、第3層は入力受付と結果案内へ限定します。これにより、コードの対象が明確になり、別シートを見ていても結果が変わりにくく、テストしやすいVBAになります。

出典メモ

  • 元資料:C:\Users\hoehoe\Downloads\記事ネタmd\excel_vba_two_operation_models.md。元資料の二分類を三層モデルへ整理し、Selectionの型検査、例外処理の局所化、処理本体と画面案内の分離、AIへの指示例を補った。関連する既存記事は、記事034「VBA Range完全解説」、記事125「ExcelとVBAで避けたいアンチパターンを整理する」。

  • Microsoft Learn「Application.Selection property (Excel)」:Selectionが現在選択されているオブジェクトを返し、対象により型が変わることを確認した。https://learn.microsoft.com/office/vba/api/Excel.application.selection (2026-08-02確認)

  • Microsoft Learn「Range.Select method (Excel)」:Rangeオブジェクトを選択するメソッドの仕様を確認した。https://learn.microsoft.com/office/vba/api/excel.range.select (2026-08-02確認)