ExcelマクロのScrollColumnを省略する方法|マクロ記録で大量にできたスクロール処理をVBAで整理

Visual Basic

Excelの「マクロの記録」を使うと、実際に行った操作がVBAコードとして自動的に記録されます。便利な機能ですが、横へ長くスクロールしただけでActiveWindow.ScrollColumn = 2ActiveWindow.ScrollColumn = 3ActiveWindow.ScrollColumn = 4……というコードが大量に生成されることがあります。

このようなコードを見て「2から88まで全部書かなければならないのか」と思うかもしれませんが、その必要はありません。途中のスクロール位置が処理結果に関係しないなら、中間のScrollColumnは基本的にすべて削除できます。

さらに、列を切り取り・コピー・移動することが目的なら、そもそも画面を目的の列までスクロールしたり、その列をSelectしたりする必要がない場合もあります。マクロ記録で生成されたコードは「操作の記録」であって「最も簡潔なVBA」ではないため、記録後に整理するのがポイントです。

ScrollColumnとは何をしているコードなのか

ActiveWindow.ScrollColumnは、Excelウィンドウの左端に表示する列を指定するプロパティです。MicrosoftのVBAリファレンスでも、ScrollColumnはウィンドウ左側に表示される列の番号を設定・取得するものと説明されています。[参照] Microsoft Learn「Window.ScrollColumn」

例えば次のコードなら、表示位置を変更して2列目のB列が左側に来るようスクロールします。

ActiveWindow.ScrollColumn = 2

同様に、

ActiveWindow.ScrollColumn = 88

なら88列目付近まで横方向にスクロールします。つまりこれはセルの値を書き換える処理ではなく、基本的にはExcel画面をどこまで横スクロールして表示するかというUI上の操作です。

2、3、4……88と1列ずつ書く必要はない

例えばマクロ記録によって次のようなコードが生成されたとします。

ActiveWindow.ScrollColumn = 2
ActiveWindow.ScrollColumn = 3
ActiveWindow.ScrollColumn = 4
ActiveWindow.ScrollColumn = 5
' ……途中省略……
ActiveWindow.ScrollColumn = 87
ActiveWindow.ScrollColumn = 88

これは人間がExcelを操作しているとき、画面が2列目、3列目、4列目……と順番にスクロールした動きをマクロ記録が拾った結果です。

最終的に88列目を表示することだけが目的なら、途中経過は必要ありません。次の1行だけで十分です。

ActiveWindow.ScrollColumn = 88

「2から88までを短く表現する」のではなく、「2から87までの処理そのものが不要なので削除する」と考えるのがポイントです。

88から1へ戻る処理も1行でよい

同じ考え方で、作業後に88、87、86、85……と順番に左へ戻っているコードも、途中の表示位置に意味がなければすべて不要です。

例えば、

ActiveWindow.ScrollColumn = 87
ActiveWindow.ScrollColumn = 86
ActiveWindow.ScrollColumn = 85
ActiveWindow.ScrollColumn = 84
' ……途中省略……
ActiveWindow.ScrollColumn = 5
ActiveWindow.ScrollColumn = 2
ActiveWindow.ScrollColumn = 1

というコードは、最終的にA列付近へ戻したいだけなら、

ActiveWindow.ScrollColumn = 1

だけで済みます。人間がマウスやスクロールバーを操作すると途中の移動過程がありますが、VBAでは最終位置を直接指定できます。

今回のようなコードなら大幅に短縮できる

例えば元の処理が「DK列まで横スクロールする→DK列を選択する→切り取る→左端へ戻る」という内容なら、マクロ記録では大量のScrollColumnが入ることがあります。

途中のスクロールを省略するだけなら、例えば次の程度まで短くできます。

Sub Sample()
    ActiveWindow.ScrollColumn = 88
    Columns("DK:DK").Select
    Selection.Cut
    ActiveWindow.ScrollColumn = 1
End Sub

ただし、ここからさらに整理できます。VBAではDK列を操作するために、DK列を画面に表示してSelectする必要はありません。

列を切り取るだけならScrollColumnもSelectも不要

VBAでは対象オブジェクトを直接指定できます。そのため「DK列を切り取る」こと自体が目的なら、次のように記述できます。

Sub Sample()
    Columns("DK:DK").Cut
End Sub

これなら横スクロールも、Selectも、Selection.Cutも必要ありません。

MicrosoftのExcel VBAドキュメントでもRangeオブジェクトにはCutメソッドが用意されており、範囲を直接切り取ることができます。[参照] Microsoft Learn「Range.Cut method」

マクロ記録を整理するときは「Selectしてから操作」ではなく「対象を直接操作できないか」を考えると、コードを大幅に短縮できます。

別の場所へ貼り付けるならDestinationを指定できる

DK列を切り取ったあと別の列へ移動したいのであれば、CutメソッドのDestinationを利用する方法があります。

例えばDK列をB列へ移動する処理なら、考え方としては次のように対象を直接指定できます。

Sub Sample()
    Columns("DK:DK").Cut Destination:=Columns("B:B")
End Sub

このように書けば「DKまでスクロール→DKを選択→切り取り→B列までスクロール→B列を選択→貼り付け」という画面操作をVBAで再現する必要がありません。

ただし列全体の切り取りは既存データへ大きな影響を与えるため、実際の目的が「列の移動」「値だけコピー」「列の挿入」のどれなのかによって適切なコードは変わります。重要なブックではコピーを作ってからテストしましょう。

それでも2~88を順番に処理したいならFor文を使う

今回のスクロールでは途中の数値を処理する必要はありませんが、VBAで本当に「2から88まで順番に何かを実行したい」場合は、同じコードを87行書く必要はありません。For…Nextステートメントを使用できます。

例えば2から88まで順番にScrollColumnへ設定するなら、次のように書けます。

Dim i As Long

For i = 2 To 88
    ActiveWindow.ScrollColumn = i
Next i

MicrosoftのVBAリファレンスでも、For…Nextは指定された回数だけ一連のステートメントを繰り返す構文として説明されています。[参照] Microsoft Learn「For…Next statement」

ただし今回のように「88まで移動したいだけ」ならFor文に置き換える必要すらなく、ActiveWindow.ScrollColumn = 88の1行が適切です。

88から1まで逆順で処理するならStep -1

何らかの理由で88、87、86……と順番に処理する必要がある場合は、For文にStep -1を指定できます。

Dim i As Long

For i = 88 To 1 Step -1
    ActiveWindow.ScrollColumn = i
Next i

これによって大量のScrollColumnを1行ずつ記述する必要はなくなります。

ただし画面を左端へ戻すだけなら、やはりループさせる必要はありません。ActiveWindow.ScrollColumn = 1と直接指定したほうが高速で、コードの意図も明確です。

大量のScrollColumnがコンパイルエラーの直接原因とは限らない

「コードの行数が多いからコンパイルエラーになった」と考えがちですが、ScrollColumnが数十行あること自体が直ちにコンパイルエラーを起こすとは限りません。

コンパイルエラーの場合は、まずVBEの「デバッグ」→「VBAProjectのコンパイル」を実行し、どの行やプロシージャで止まるか確認します。構文の間違い、対応していないEnd IfやNext、変数宣言、プロシージャサイズなど、エラー内容によって原因は異なります。

MicrosoftのVBA仕様には、1つのプロシージャについてコンパイル後のコードが64KBを超えると「Procedure too large」というエラーが発生することも記載されています。[参照] Microsoft Learn「Procedure too large」

マクロ記録によって非常に巨大な1つのSubが作られている場合には、この制限に達する可能性があります。その場合も不要なSelect・ScrollColumnの削除や、処理を複数のSubへ分割することが有効です。

マクロ記録ではなぜ無駄に見えるコードが大量にできるのか

Excelのマクロ記録は、人間が行った操作をVBAとして記録する機能です。「この人が最終的に何をしたいのか」を理解して、最短アルゴリズムへ自動変換する機能ではありません。

そのため人間がDK列を見るために横スクロールすると、その途中のスクロール操作も記録されます。セルをクリックすればSelectが入り、コピーすればSelection.Copyのようなコードになります。

これはマクロ記録の欠点というより役割の違いです。VBAの書き方が分からない操作を一度記録して、生成されたオブジェクト名やメソッドを調べるための「コード作成の手掛かり」として使うと便利です。

Select・Selection・Activateを減らすとコードが短く安定する

マクロ記録から生成されたコードを整理するときは、ScrollColumnだけでなくSelectSelectionActivateにも注目します。

例えば、

Columns("DK:DK").Select
Selection.Cut

は、

Columns("DK:DK").Cut

と直接書けます。同様に、

Range("A1").Select
Selection.Value = "完了"

は、

Range("A1").Value = "完了"

と書けます。

このように対象を直接操作すると、コード量が減るだけでなく、途中で別のセルやシートが選択されたことによる誤動作も防ぎやすくなります。

ActiveSheetではなくワークシートも明示するとさらに安全

Columns("DK:DK").Cutだけでは、基本的に現在アクティブなシートが対象になります。複数シートを扱うマクロなら、どのワークシートなのか明示したほうが安全です。

例えば「Sheet1」のDK列を切り取るなら、次のようにできます。

Sub Sample()
    ThisWorkbook.Worksheets("Sheet1").Columns("DK:DK").Cut
End Sub

こうしておけば、ユーザーが別のシートを選択していても対象を明確にできます。マクロ記録を実務用コードへ整理するときには、「画面で現在選ばれているもの」への依存を減らすことが重要です。

画面のちらつきを抑えるならScreenUpdatingも検討する

大量の処理を実行するマクロでは、画面が頻繁に切り替わったりスクロールしたりすると見た目がちらつき、実行速度にも影響することがあります。

その場合は処理開始時にApplication.ScreenUpdating = False、終了時にApplication.ScreenUpdating = Trueとする方法があります。MicrosoftもScreenUpdatingをオフにするとマクロを高速化できると説明しています。[参照] Microsoft Learn「Application.ScreenUpdating」

ただし、ScrollColumn自体が不要なら「画面更新を隠して大量スクロールする」より、スクロール処理そのものを削除するほうがシンプルです。

今回のケースを整理するとどう書けばよい?

目的別に整理すると、コードは次のように考えられます。

目的 コードの考え方
88列目を表示したいだけ ActiveWindow.ScrollColumn = 88
左端へ戻したいだけ ActiveWindow.ScrollColumn = 1
2~88を本当に順番に処理したい For i = 2 To 88を使う
88~1を順番に処理したい For i = 88 To 1 Step -1を使う
DK列を切り取りたいだけ Columns("DK:DK").Cut

特にDK列を切り取ることだけが目的なら、ScrollColumnは2~88だけでなく全部削除できる可能性があります。画面にDK列が見えていなくても、VBAは直接DK列を操作できるからです。

まとめ:マクロ記録のスクロール処理は「省略」ではなく削除できる

Excelのマクロ記録でActiveWindow.ScrollColumn = 2から88まで大量のコードが作成された場合、最終的に88列目を表示したいだけなら途中の3、4、5……87を記述する必要はありません。ActiveWindow.ScrollColumn = 88と直接指定できます。

88から1へ戻る場合も同様で、途中の87、86、85……をすべて削除してActiveWindow.ScrollColumn = 1とできます。本当に連番処理が必要な場合だけFor…Nextを利用します。

さらに今回のように目的がColumns("DK:DK").SelectしてSelection.Cutすることなら、Columns("DK:DK").Cutと直接書けば、横スクロールもSelectも不要です。

また、数十行のScrollColumnがあるだけで必ずコンパイルエラーになるわけではありません。実際のエラーメッセージも確認してください。巨大なマクロで「Procedure too large」が出ている場合は、不要な記録コードを削除し、処理を複数のSubへ分割する方法が有効です。

マクロ記録は完成コードを自動的に最適化する機能ではなく、Excel操作をVBAへ変換してくれる学習・作成支援ツールとして考えると便利です。記録後にScrollColumn、Select、Selection、Activateなどを見直し、「操作の再現」から「対象を直接処理するコード」へ書き換えることで、短く高速で安定したマクロにできます。

コメント

タイトルとURLをコピーしました