【VBA】処理の進捗をステータスバーに表示する方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク

この記事でできること

1000行のデータ処理マクロを実行した。画面が固まったまま動かない。あと何分かかるのかわからない。

「フリーズしたのか、それとも処理中なのか」——判断がつかない。2分待って、3分待って、不安になってExcelを強制終了してしまった。再度開いたら、処理が中途半端に終わっていてデータがおかしくなっていた。

この記事のVBAを使えば、マクロ実行中にステータスバーへ「350 / 1000 件処理中… 経過: 00:01:23」と進捗が表示されます。動いていることが一目でわかる。あとどれくらいかも見える。不安で途中終了させてしまう事故がゼロになります。

  • 対象:マクロの処理中に不安を感じたことがある人。VBAを知らなくてOK
  • 所要時間:コピペ → 実行まで約5分

完成イメージ(Before / After)

Before(進捗表示なし)

Before(実行前)のExcel画面
A B
1 状態 表示
2 画面固まる (何も表示されない)
3 応答なし フリーズ?処理中?
4 不安で強制終了 データが壊れた

After(進捗表示あり)

After(実行後)のExcel画面
A B
1 状態 ステータスバー表示
2 処理中 350 / 1000 件処理中…
3 処理中 700 / 1000 件処理中…
4 完了 処理完了(1000件)

進捗が見えるから安心して待てる。強制終了の事故がゼロに。

あの時「150 / 500 件処理中…」とステータスバーに表示されていれば、安心して待てたはずだ。実際にStatusBarを1行追加しただけで、大量ファイル統合(複数Excelファイルを1つに統合)の処理中も「ちゃんと動いてる」と分かるようになった。

この記事では、マクロ実行中に進捗を表示する方法を最小版と実務版の2パターンで紹介する。まずは最小版をコピペして、ステータスバーの手軽さを体験してほしい。

ステータスバーに進捗を出すだけで、マクロ実行中の「動いてるのか分からない」不安がなくなる。

どんな場面で使う?

  • 大量ファイルの処理中に「今何件目か」を表示して安心感を出したい
  • マクロ実行中に画面が固まったように見えて同僚から「フリーズした?」と聞かれる
  • 長時間処理のマクロを同僚に渡すとき、進捗が分からないと不安がられる
  • 処理完了までの見込み時間を表示して、待ち時間のストレスを減らしたい

実行前の準備

バックアップを取る

マクロ実行前に、Excelファイルのコピーを別フォルダに保存しておく。進捗表示の追加自体はデータを壊す操作ではないが、大量データを処理するマクロに組み込む以上、バックアップは習慣にしておく。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロは保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す
  2. VBE(Visual Basic Editor)が開く

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 白い画面(コードウィンドウ)が表示される

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. 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"

コードの流れ

  1. シートと最終行の取得: 処理対象のシートとデータの最終行を特定する
  2. ループ処理: 各行に対して処理を実行する
  3. StatusBar更新: ループの中で「○件 / ○件 処理中…」とステータスバーに表示する
  4. リセット: 処理完了後に 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

コードの流れ

  1. ScreenUpdating=False: 画面更新を停止して高速化する
  2. On Error GoTo ErrHandler: エラー発生時に必ず ScreenUpdating=True に復帰するための安全策(エラー処理の詳細は VBAのエラー処理入門 を参照)
  3. 最終行の取得: データの範囲を自動検出する
  4. Timer で開始時刻を記録: 処理時間の計測を開始する
  5. N件ごとにStatusBar更新: 毎ループではなく updateInterval 件ごとに更新(パフォーマンス維持)
  6. DoEvents: OSに制御を返し、「応答なし」を防ぎつつStatusBarの表示を更新する
  7. 完了処理: 経過時間を含む完了メッセージをMsgBoxで表示し、StatusBarをリセットする
  8. エラーハンドラ: エラー時も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を呼んでいた。1000行の処理が30秒から2分に増えて「高速化どころか遅くなった」と焦った。updateIntervalで間引くだけで元の速度に戻った。

原因: ループの中で毎回 DoEvents を呼んでいる。DoEvents は OS に制御を返す処理で、毎回呼ぶとオーバーヘッドが大きい。

対策: updateInterval(初期値10)件ごとに1回だけ呼ぶ。1000件のデータなら100回の DoEvents で済む。データ量が多い場合は updateInterval を50〜100に増やす。

5. Timer の値がマイナスになる

原因: Timer は午前0時からの経過秒数を返す。日付をまたぐ処理では0時にリセットされ、Timer - startTime がマイナスになる。

対策: 日付をまたぐ可能性がある処理では、Timer の代わりに Now を使う。通常の業務時間内の処理であれば Timer で問題ない。

VBAのステータスバーに進捗が表示されないときの対処法

「StatusBarに値を設定したのに何も表示されない」という場合、原因は Application.DisplayStatusBar = False になっていることだ。コードの先頭に Application.DisplayStatusBar = True を追加し、処理完了後に Application.StatusBar = False でリセットすれば正しく表示される。

VBAで進捗表示を入れたら処理が遅くなったときの対処法

「進捗表示を追加したら処理速度が半分になった」という場合、原因はループの全回にStatusBar更新を入れていることだ。1万回のループなら100回に1回(If i Mod 100 = 0 Then)だけ更新するようにすれば、速度をほぼ維持しつつ進捗表示ができる。

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)
  • 進捗表示があるだけで、大量データ処理の「動いてるのか分からない」不安がなくなる

関連記事

次にやりたくなること

進捗表示があるだけで、マクロ実行中の不安がゼロになる。まずは最小版でStatusBarの手軽さを体験してみてほしい。

コメント

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