Contents
この記事でできること
- VBAマクロ実行中にステータスバーへ「○○件 / ○○件 処理中…」と進捗を表示できる
- ScreenUpdating=False で処理速度を2〜5倍に高速化しながら、進捗表示も維持できる
- DoEvents で「応答なし」表示を防ぎ、経過時間もリアルタイムで確認できる
対象: Excel 2016以降 / Microsoft 365、Windows 10/11
完成イメージ(Before / After)
Before(進捗表示なし):
- マクロを実行する
- 画面が固まる
- タスクバーに「応答なし」と表示される
- 動いてるのか止まってるのか分からず不安
- 怖くなって強制終了→中途半端な状態に
After(進捗表示あり):
- マクロを実行する
- ステータスバーに「150 / 1000 件処理中… 経過: 00:01:23」と表示される
- 画面はフリーズせず、進捗が目に見える
- 安心して待てる。完了時に「処理完了」と表示される
500件のファイル処理マクロを実行したことがある。画面が固まって、ステータスバーには何も表示されない。1分経っても2分経っても画面は真っ白のまま。動いてるのか止まってるのか分からず、10分待った末に怖くなって強制終了した。結果、半分だけ処理された中途半端な状態になり、どこまで終わったのかを手作業で確認する羽目になった。
あの時「150 / 500 件処理中…」とステータスバーに表示されていれば、安心して待てたはずだ。実際にStatusBarを1行追加しただけで、大量ファイル統合(複数Excelファイルを1つに統合)の処理中も「ちゃんと動いてる」と分かるようになった。
この記事では、マクロ実行中に進捗を表示する方法を最小版と実務版の2パターンで紹介する。まずは最小版をコピペして、ステータスバーの手軽さを体験してほしい。
ステータスバーに進捗を出すだけで、マクロ実行中の「動いてるのか分からない」不安がなくなる。
実行前の準備
バックアップを取る
マクロ実行前に、Excelファイルのコピーを別フォルダに保存しておく。進捗表示の追加自体はデータを壊す操作ではないが、大量データを処理するマクロに組み込む以上、バックアップは習慣にしておく。
Excelをマクロ有効ブック(.xlsm)で保存する
拡張子が .xlsx のままだとマクロは保存できない。
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
- 保存
手順(コピペ → 実行まで約5分)
VBE(コードを書く画面)を開く
- Excelで
Alt + F11を押す - VBE(Visual Basic Editor)が開く
標準モジュールを挿入する
- VBEのメニュー →「挿入」→「標準モジュール」
- 白い画面(コードウィンドウ)が表示される
コードを貼り付けて実行する
- コードウィンドウに、下のコードをそのままコピペする
Alt + F8→ マクロ名を選んで「実行」
コード(最小版)– ステータスバーに処理件数を表示
'============================================================
' ■ ステータスバーに処理件数を表示(最小版)
' → ループ処理の進捗をステータスバーで確認できる
' → 処理完了後にステータスバーをリセットする
'============================================================
Sub ShowProgressMinimal()
'--- ★書き換えポイント ---
Dim wsName As String
wsName = "Sheet1" '← 処理対象のシート名
Dim startRow As Long
startRow = 2 '← データの開始行(1行目がヘッダーなら2)
Dim dataCol As String
dataCol = "A" '← データが入っている列
'--- ★ここまで ---
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(wsName)
'--- 最終行を取得
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, dataCol).End(xlUp).Row
Dim totalCount As Long
totalCount = lastRow - startRow + 1
'--- ループ処理(ここに実際の処理を書く)
Dim i As Long
For i = startRow To lastRow
'=== ここに1行ごとの処理を書く ===
'(例)セルの値を読み取って何かする
' Dim val As String
' val = ws.Cells(i, dataCol).Value
'=================================
'--- ステータスバーに進捗を表示
Application.StatusBar = (i - startRow + 1) & " / " & totalCount & " 件処理中..."
Next i
'--- 処理完了:ステータスバーをリセット
Application.StatusBar = False
MsgBox totalCount & " 件の処理が完了しました。", vbInformation
End Sub
書き換えポイント
| 変数 | 説明 | 初期値 |
|---|---|---|
| `wsName` | 処理対象のシート名 | `”Sheet1″` |
| `startRow` | データの開始行 | `2`(1行目ヘッダー想定) |
| `dataCol` | データが入っている列 | `”A”` |
コードの流れ
- シートと最終行の取得: 処理対象のシートとデータの最終行を特定する
- ループ処理: 各行に対して処理を実行する
- StatusBar更新: ループの中で「○件 / ○件 処理中…」とステータスバーに表示する
- リセット: 処理完了後に
Application.StatusBar = Falseでステータスバーを元に戻す
テスト方法: A列に適当なデータを100行ほど入れて実行する。ステータスバー(Excel下部)に件数が表示されれば成功。フォルダ内のファイル一覧を取得する処理(フォルダ内ファイル一覧を自動取得)と組み合わせて、ファイル処理の進捗を表示することもできる。
コード(実務版)– 高速化+応答維持+経過時間表示
実務では1000行を超えるデータを処理することが珍しくない。最小版のまま大量データを流すと、処理は遅いし画面はチカチカするし、タスクバーに「応答なし」が出る。
以前、DoEventsを入れずに1000行の生産データを処理したら、タスクバーに「応答なし」と表示されて上司に「パソコン壊れた?」と聞かれた。DoEventsを1行追加するだけで応答なし表示が消えて、ステータスバーの進捗もスムーズに更新されるようになった。
実務版では以下の3つを追加する:
- ScreenUpdating=False: 画面更新を止めて処理速度を2〜5倍に高速化
- DoEvents: OSに制御を返して「応答なし」表示を防ぎ、StatusBarの表示も更新する
- 経過時間表示: Timer関数で処理開始からの経過時間を「hh:mm:ss」形式で表示
複数シート処理(複数シートを一括処理する方法)のように対象が多い場合は、この実務版を使うことを推奨する。
'============================================================
' ■ 進捗表示+高速化+応答維持(実務版)
' → ScreenUpdating=False で高速化
' → DoEvents で「応答なし」防止+StatusBar更新
' → Timer で経過時間を表示
' → エラー時も ScreenUpdating=True に復帰する
'============================================================
Sub ShowProgressAdvanced()
'--- ★書き換えポイント ---
Dim wsName As String
wsName = "Sheet1" '← 処理対象のシート名
Dim startRow As Long
startRow = 2 '← データの開始行
Dim dataCol As String
dataCol = "A" '← データが入っている列
Dim updateInterval As Long
updateInterval = 10 '← 何件ごとにステータスバーを更新するか
'--- ★ここまで ---
'--- 画面更新を停止(高速化)
Application.ScreenUpdating = False
'--- エラー時にScreenUpdating=Trueに復帰するためのエラー処理
On Error GoTo ErrHandler
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(wsName)
'--- 最終行を取得
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, dataCol).End(xlUp).Row
Dim totalCount As Long
totalCount = lastRow - startRow + 1
'--- 開始時刻を記録
Dim startTime As Double
startTime = Timer
'--- ループ処理
Dim i As Long
For i = startRow To lastRow
'=== ここに1行ごとの処理を書く ===
'(例)セルの値を読み取って何かする
' Dim val As String
' val = ws.Cells(i, dataCol).Value
'=================================
'--- N件ごとにステータスバーを更新(毎回更新すると遅くなる)
If (i - startRow + 1) Mod updateInterval = 0 Or i = lastRow Then
'--- 経過時間を計算
Dim elapsed As Double
elapsed = Timer - startTime
'--- 経過時間を hh:mm:ss 形式に変換
Dim elapsedStr As String
elapsedStr = Format(elapsed / 86400, "hh:nn:ss")
'--- ステータスバーに進捗+経過時間を表示
Application.StatusBar = _
(i - startRow + 1) & " / " & totalCount & " 件処理中... " & _
"経過: " & elapsedStr
'--- OSに制御を返す(応答なし防止+StatusBar更新)
DoEvents
End If
Next i
'--- 処理完了:経過時間を含む完了メッセージ
Dim totalElapsed As String
totalElapsed = Format((Timer - startTime) / 86400, "hh:nn:ss")
Application.StatusBar = "処理完了(" & totalCount & "件 / 経過: " & totalElapsed & ")"
'--- 画面更新を再開
Application.ScreenUpdating = True
MsgBox totalCount & " 件の処理が完了しました。" & vbCrLf & _
"経過時間: " & totalElapsed, vbInformation
'--- 3秒後にステータスバーをリセット(完了メッセージを少し残す)
Application.StatusBar = False
Exit Sub
ErrHandler:
'--- エラー時もScreenUpdatingを必ず復帰させる
Application.ScreenUpdating = True
Application.StatusBar = False
MsgBox "エラーが発生しました。" & vbCrLf & _
"エラー番号: " & Err.Number & vbCrLf & _
"内容: " & Err.Description, vbCritical
End Sub
書き換えポイント
| 変数 | 説明 | 初期値 |
|---|---|---|
| `wsName` | 処理対象のシート名 | `”Sheet1″` |
| `startRow` | データの開始行 | `2` |
| `dataCol` | データが入っている列 | `”A”` |
| `updateInterval` | 何件ごとにステータスバーを更新するか | `10` |
コードの流れ
- ScreenUpdating=False: 画面更新を停止して高速化する
- On Error GoTo ErrHandler: エラー発生時に必ず ScreenUpdating=True に復帰するための安全策(エラー処理の詳細は VBAのエラー処理入門 を参照)
- 最終行の取得: データの範囲を自動検出する
- Timer で開始時刻を記録: 処理時間の計測を開始する
- N件ごとにStatusBar更新: 毎ループではなく
updateInterval件ごとに更新(パフォーマンス維持) - DoEvents: OSに制御を返し、「応答なし」を防ぎつつStatusBarの表示を更新する
- 完了処理: 経過時間を含む完了メッセージをMsgBoxで表示し、StatusBarをリセットする
- エラーハンドラ: エラー時もScreenUpdating=TrueとStatusBar=Falseを実行して安全に復帰する
ScreenUpdating=False にした処理は、必ずエラー処理で True に戻す仕組みを入れておく。これを忘れると画面が真っ白になる。詳しくは VBAのエラー処理入門 を参照。
よくある落とし穴5選
1. 処理完了後もステータスバーにメッセージが残ったまま
原因: Application.StatusBar = False を書き忘れている。
対策: ループの後に必ず Application.StatusBar = False を入れる。エラーハンドラの中にも入れておく(実務版コード参照)。
2. ScreenUpdating=False のまま止まって画面が真っ白に
原因: エラーで処理が中断し、ScreenUpdating = True に戻る前にマクロが終了した。
自分もこれをやった。ScreenUpdating=Falseにしたら処理が3倍速くなって喜んでいたが、途中でエラーが出て止まった時にTrueに戻し忘れてExcelの画面が真っ白になった。セルをクリックしても何も表示されない。VBEを開いてイミディエイトウィンドウに Application.ScreenUpdating = True と入力して実行したらようやく復帰した。それ以来、On Error GoTo でScreenUpdatingの復帰を必ず書くようにしている。
対策: 実務版コードのように On Error GoTo ErrHandler で、エラー時も ScreenUpdating = True に戻す処理を入れる。
3. StatusBarの表示が更新されない
原因: ScreenUpdating = False の状態では、StatusBarの表示更新も止まることがある。
対策: StatusBarを更新した直後に DoEvents を呼ぶ。実務版コードではN件ごとにDoEventsを呼んでいる。
4. DoEventsを入れたら処理が遅くなった
原因: ループの中で毎回 DoEvents を呼んでいる。DoEvents は OS に制御を返す処理で、毎回呼ぶとオーバーヘッドが大きい。
対策: updateInterval(初期値10)件ごとに1回だけ呼ぶ。1000件のデータなら100回の DoEvents で済む。データ量が多い場合は updateInterval を50〜100に増やす。
5. Timer の値がマイナスになる
原因: Timer は午前0時からの経過秒数を返す。日付をまたぐ処理では0時にリセットされ、Timer - startTime がマイナスになる。
対策: 日付をまたぐ可能性がある処理では、Timer の代わりに Now を使う。通常の業務時間内の処理であれば Timer で問題ない。
FAQ
Q1: ステータスバーはどこに表示される?
Excelウィンドウの一番下にある細い帯がステータスバー。通常は「準備完了」や選択範囲の合計値が表示されている場所。Application.StatusBar に文字列を代入すると、ここに任意のテキストが表示される。
Q2: UserForm のプログレスバーとどちらがいい?
手軽さならStatusBar。見た目のインパクトならUserFormのプログレスバー。StatusBarはコード1行で表示できるので、既存のマクロに進捗表示を追加するならStatusBarが圧倒的に楽。UserFormは見栄えは良いが、フォーム作成+表示制御のコードが必要で手間がかかる。
Q3: ボタンクリックで進捗付きマクロを実行したい
ボタン設置(マクロをボタン1つで実行する方法)と組み合わせれば、ワンクリックで進捗表示付きの処理が走る。ボタンの OnAction に進捗表示付きマクロ名を指定するだけ。
Q4: ScreenUpdating=False にしなくても進捗は表示される?
される。最小版コードは ScreenUpdating を操作していないが、ステータスバーは更新される。ただし画面が毎行更新されるため処理が遅く、画面がチカチカする。大量データ(100行以上)を処理するなら、実務版の ScreenUpdating=False を推奨する。
Q5: 経過時間ではなく残り時間を表示したい
現在の処理速度から概算できる:
Dim progress As Double
progress = (i - startRow + 1) / totalCount
Dim remaining As Double
remaining = elapsed / progress - elapsed
Application.StatusBar = "残り約 " & Format(remaining / 86400, "hh:nn:ss")
ただし処理速度が一定でないと誤差が大きくなるため、あくまで目安として表示する。
まとめ
Application.StatusBar = "テキスト"でステータスバーに進捗を表示できる- 処理完了後は
Application.StatusBar = Falseで必ずリセットする ScreenUpdating = Falseで処理を高速化し、DoEventsでStatusBarの更新と「応答なし」防止を両立する- エラー時に
ScreenUpdating = Trueに戻す処理を必ず入れる(On Error GoTo) - 進捗表示があるだけで、大量データ処理の「動いてるのか分からない」不安がなくなる
関連記事
- 複数Excelファイルを1つに統合 — 大量ファイル統合で進捗表示が活きる場面
- 複数シートを一括処理する方法 — シート数が多い処理にも進捗表示を組み込める
- VBAのエラー処理入門 — ScreenUpdating復帰に必須のエラー処理を学ぶ
次にやりたくなること
- ExcelファイルをPDFに一括変換: 大量のPDF変換処理で進捗表示を組み合わせると、何枚目まで完了したか一目で分かる
- バックアップを自動化する方法: 大量ファイルのバックアップ処理にも進捗表示を追加して、安心して待てるようにする
進捗表示があるだけで、マクロ実行中の不安がゼロになる。まずは最小版でStatusBarの手軽さを体験してみてほしい。


コメント