【入門編】【中級】Application.SysCmdを活用した、長時間のデータ処理における進捗バーの実装 – Access VBA解析バイブル

スポンサーリンク

こんにちは!Access VBAの奥深い世界へようこそ。チーフアーキテクトの私です。

マクロのボタンを押したはいいものの、画面がピクリとも動かなくなり、「これ、フリーズしてるの?それとも頑張って計算中なの…?」と、冷や汗をかきながら画面の前で祈った経験はありませんか?

数万件ものデータをガッツリ処理するバッチ処理において、「ユーザーを不安にさせないこと」は、プロのエンジニアにとって極めて重要な作法です。

今回は、Access標準の隠し武器とも言える `Application.SysCmd` メソッドを駆使して、ステータスバーに美しく滑らかな進捗バー(プログレスバー)を実装する方法を伝授します。ここをクリアすれば、あなたの作るAccessアプリは一気に「プロのシステム」へと生まれ変わりますよ。さあ、一緒に扉を開けましょう!

なぜ `SysCmd` なのか?(オブジェクトモデルの知見)

Access VBAで進捗バーを作ろうとすると、フォームに「カニ歩き」させるような独自のバーを作りがちです。しかし、重いデータ処理の最中に複雑なフォームの再描画(Repaint)を行うと、それ自体がパフォーマンスのボトルネック(足かせ)になります。

そこで登場するのが、Accessのアプリケーション自体が持っている機能、`Application.SysCmd` です。
ステータスバーという「OSおよびAccessが管理する領域」を直接叩くため、余計な描画負荷をかけず、極めて軽量かつ確実に進捗を伝えることができます。

実装の全体像とステップ

進捗バーを正しく機能させるためのステップは、たったの3つです。

1. 初期化(Initialization):バーの「ゼロ地点」を設定し、タイトルを決める。
2. 更新(Update):レコードを1件処理するごとに、バーの目盛りを1つ進める。
3. 終了(Removal):処理が終わったら、ステータスバーを元の綺麗な状態に戻す。

これをコードに落とし込むと、美しいライフサイクルが完成します。

実践!コピペで使える極上のサンプルコード

以下のコードは、実際の業務システムでそのまま使える堅牢なテンプレートです。
今回は `CurrentDb` を使ってテーブルの全レコードを走査するシーンを想定しています。

Public Sub RunHeavyDataProcessWithProgress()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim lngTotalCount As Long
Dim lngCurrentCount As Long

‘ データベースとレコードセットの参照を取得
Set db = CurrentDb
Set rs = db.OpenRecordset(“T_大規模データ”, dbOpenSnapshot)

‘ レコードが空の場合は即座に抜ける(ゼロ除算や無駄な処理を防ぐ防衛策)
If rs.RecordCount = 0 Then
MsgBox “処理対象のデータが存在しません。”, vbInformation, “お知らせ”
GoTo Cleanup
End If

‘ 【重要】正確な全件数を取得するために最後まで移動する
rs.MoveLast
lngTotalCount = rs.RecordCount
rs.MoveFirst

‘ —————————————————————–
‘ Step 1: SysCmdによる進捗バーの初期化
‘ 引数 4 は「進捗バーの表示」、タイトル、最大値を指定します
‘ —————————————————————–
SysCmd acSysCmdInitMeter, “データを精査・処理しています…”, lngTotalCount

lngCurrentCount = 0

‘ メインのループ処理
Do Until rs.EOF

‘ ————————————————————-
‘ ここに実際の重い処理(データの加工、他テーブルへの書き込みなど)を書く
‘ ————————————————————-
‘ 例として、ダミーのウェイト(処理の擬似再現)は入れず、そのまま進めます

‘ カウントを進める
lngCurrentCount = lngCurrentCount + 1

‘ ————————————————————-
‘ Step 2: 10件に1回など、適度な頻度でバーを更新(パフォーマンス最適化)
‘ 毎件更新するとVBAの描画が追いつかず遅くなるため間引くのがプロの技
‘ ————————————————————-
If lngCurrentCount Mod 10 = 0 Or lngCurrentCount = lngTotalCount Then
SysCmd acSysCmdUpdateMeter, lngCurrentCount
End If

rs.MoveNext
Loop

MsgBox “すべての処理が正常に完了しました!”, vbInformation, “完了”

Cleanup:
‘ —————————————————————–
‘ Step 3: 必ずステータスバーをクリアして初期状態に戻す
‘ これを忘れると、Accessの下部に変なバーが残り続けます(重要!)
‘ —————————————————————–
SysCmd acSysCmdRemoveMeter

‘ オブジェクトの解放(メモリリークの根絶)
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set db = Nothing

End Sub

コードの急所:ここが分かればもう迷わない!

1. `rs.MoveLast` の意味を知る

DAOのレコードセットを開いた直後、`RecordCount` プロパティは「実際にアクセスした件数」しか正確に返さないことがあります(特にダイナセット型など)。そのため、一度 `MoveLast` で最後のレコードまで強制的にジャンプさせ、テーブル全体の総数を正確に把握してから進捗バーの最大値(`lngTotalCount`)に設定するのが鉄則です。

2. `Mod`(剰余演算子)による描画の間引き

数万件もあるループの中で、毎回 `SysCmd acSysCmdUpdateMeter` を呼ぶと、VBAの処理速度がステータスバーの描画に引っ張られて数倍遅くなります。
`If lngCurrentCount Mod 10 = 0` を使うことで、「10件に1回だけ画面を更新する」という賢い間引きを行い、処理速度を落とさずに滑らかなバーを実現できます。この気配りがエンジニアの腕の見せ所です。

3. クリーニング(`acSysCmdRemoveMeter`)の絶対厳守

エラーが起きた時や処理が途中で終わった時でも、必ずステータスバーを元に戻さなければなりません。サンプルコードのように `GoTo Cleanup` などのエラーハンドリング・終了ルートを必ず用意し、`acSysCmdRemoveMeter` を通る構造にしてください。

よくある落とし穴とエラー対策

  • 「ステータスバーに何も表示されない?」

Accessのオプションで「ステータス バーを表示する」のチェックが外れていると見えません。アプリ全体の仕様としてステータスバーが表示設定になっていることを確認してください。

  • 「途中でフリーズしたように止まる」

処理があまりに重い場合、VBAがOSに制御を返さなくなることがあります。あまりに巨大なループの場合は、適宜 `DoEvents` 関数を挟むことでOSのフリーズを回避できますが、`SysCmd` を使っていればある程度システムが描画の呼吸をしてくれます。

おわりに:ここをクリアすれば、Access VBAの基本はバッチリですよ

いかがでしたでしょうか?
単に動くだけのコードから、「使う人の心地よさ」まで配慮したコードへ。このステップを踏み出したあなたなら、もうマクロの記録や初歩的な記述で躓くことはありません。

大規模なデータを扱う現場において、ユーザーとの対話(フィードバック)をデザインすることは極めて価値の高いスキルです。ぜひ今日のコードをご自身のAccess環境にブートストラップして、その滑らかな動きを体感してみてください。

それでは、次回のアーキテクチャ解説でお会いしましょう。あなたのAccess開発ライフが素晴らしいものになりますように!

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