Accessで「進捗が見えない」という罪:SysCmdとAbsolutePositionで制御するプログレスバーの極意
現場で動くAccessツールを開発しているとき、最もユーザーを不安にさせるのは「計算中…」のまま画面が固まる瞬間だ。Windowsのプロセッサは高速だが、DAO経由で数万件のレコードを回す処理は、GUIにとって「数秒間の死」を意味する。
ユーザーは「フリーズした」と勘違いし、Ctrl+Alt+Deleteで強制終了させる。これがデータベース破損の引き金になる。
プログレスバーは単なる装飾ではない。ユーザーとの信頼関係を維持するための「通信手段」だ。 今回は、DAO.Recordsetと`SysCmd`を組み合わせ、計算コストを最小限に抑えつつ、堅牢に進捗を可視化するアーキテクチャを伝授する。
—
1. なぜ「毎ループ更新」が罪なのか
初心者がやりがちなのが、ループのたびに `SysCmd(acSysCmdUpdateMeter, …)` を呼び出すコードだ。
‘ 悪い例:毎ループ更新はオーバーヘッドの塊
Do Until rs.EOF
‘ …処理…
i = i + 1
SysCmd acSysCmdUpdateMeter, i ‘ 毎回OSに描画要求を出すのは非効率
rs.MoveNext
Loop
GUIの描画更新は、CPU処理と比較して圧倒的に低速だ。毎ループ更新を行うと、本来の処理時間よりも「進捗バーを描画する時間」の方が長くなるという本末転倒な事態に陥る。
原則:更新頻度は「1%ごと」または「一定件数ごと」に絞れ。
—
2. 堅牢な設計:進捗制御クラスの考え方
進捗バーの制御には、必ず終了処理(`acSysCmdRemoveMeter`)がセットになる。例外が発生しても確実にクリーンアップされるよう、構造化例外処理(`On Error GoTo`)は必須だ。
実践的なプロダクションコード
以下のコードは、DAO.Recordsetの `AbsolutePosition` を活用し、進捗を精密に制御するテンプレートだ。
Public Sub ProcessLargeData()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim totalCount As Long
Dim currentPos As Long
Dim lastProgress As Long
Set db = CurrentDb
Set rs = db.OpenRecordset(“SELECT FROM T_LargeData”, dbOpenDynaset)
If rs.EOF Then Exit Sub
‘ 全レコード数を取得(進捗計算の母数)
rs.MoveLast
totalCount = rs.RecordCount
rs.MoveFirst
‘ プログレスバーの初期化
SysCmd acSysCmdInitMeter, “データ処理中…”, totalCount
On Error GoTo Cleanup
Do Until rs.EOF
‘ — ここに重いビジネスロジックを記述 —
‘ DoEvents ‘ 必要に応じてGUIの応答性を確保するが、過用は禁物
‘ 現在位置を取得 (0ベースなので+1する)
currentPos = rs.AbsolutePosition + 1
‘ 1%単位で更新することで描画負荷を劇的に抑える
If (currentPos Mod (totalCount \ 100 + 1)) = 0 Then
SysCmd acSysCmdUpdateMeter, currentPos
End If
rs.MoveNext
Loop
Cleanup:
‘ 異常終了時も確実にバーを消去する
SysCmd acSysCmdRemoveMeter
If Not rs Is Nothing Then
rs.Close
Set rs = Nothing
End If
Set db = Nothing
If Err.Number <> 0 Then
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub
—
3. 実務で知っておくべき「落とし穴」
RecordCountの罠
`DAO.Recordset` の `RecordCount` は、全レコードを読み込まないと正確な値を返さない場合がある(特に `dbOpenDynaset` や `dbOpenSnapshot` 使用時)。必ず最初に `rs.MoveLast` を実行し、レコードセットを最後まで一度走査させてから計算に使うこと。
DoEventsの諸刃の剣
ループ内に `DoEvents` を入れると、ユーザーが他のボタンを押せるようになる。これは一見親切だが、「処理中にユーザーが別の処理を開始し、データ整合性が壊れる」リスクを孕む。業務ツールであれば、進捗中はフォームのボタンを `Enabled = False` にするなどの排他制御とセットで運用すべきだ。
計算負荷の最適化
`currentPos Mod (totalCount \ 100 + 1)` という式は、レコード数が1万件あっても100回しか描画更新を行わない。この「描画コストの圧縮」こそが、大規模データ処理におけるプロフェッショナルのコードだ。
—
結論:エンジニアの美学
Access VBAは古臭い言語だと言われることもある。だが、オブジェクトのライフサイクルを理解し、OSのリソースをいかに効率よく使いこなすかを考える姿勢は、どんなモダンな言語であっても変わらない「エンジニアの素養」そのものだ。
進捗バーひとつ取っても、そこには「ユーザーを待たせない」「システムを壊さない」というエンジニアの哲学が宿る。ぜひ、このコードをあなたのツールに組み込み、一歩先の「プロの品質」を実現してほしい。
