【入門編】【中級】DAO.Recordsetの「AbsolutePosition」を活用した、進捗バーの動的更新とユーザー体験の向上 – Access VBA解析バイブル

スポンサーリンク

こんにちは! Access VBAの世界へようこそ。
日々、大量のデータを扱うシステムを作っていると、こんな壁にぶつかりませんか?

「数万件のレコードを一括処理している間、画面が真っ白になってフリーズしたように見える……。ユーザーから『先生、これ固まってますよ?』って言われちゃうんだよね」

分かります。処理が裏でどれだけ頑張っていても、画面がピクリとも動かないと、ユーザーは不安になって強制終了したくなるものです。

今回は、そんな「フリーズの誤解」を華麗に解消し、プロっぽい親切なシステムに生まれ変わらせるための秘訣――DAO.Recordsetの `AbsolutePosition` を使った進捗バー(ステータスバー)の動的更新テクニックを授けましょう。

ここをクリアすれば、あなたの作るAccessアプリの「ユーザー体験(UX)」は一気にプロの領域へジャンプアップします。一緒にマスターしていきましょう!

1. なぜ「フリーズした」と誤解されるのか?

Access VBAで `CurrentDb.Execute` や `Update` などのクエリ・一括処理を実行すると、VBAはその処理が完了するまで他の操作を受け付けなくなります。

人間は、「進捗が見えない待ち時間」を、実際よりも3倍長く感じるという心理データがあります。
だからこそ、今「全体のうちどのくらい進んでいるのか」を視覚的に伝えることが、業務システムにおいては極上の優しさなのです。

アクセスの隠れた名機能「ステータスバー」

進捗を表示するやり方は色々ありますが、一番手軽でスマートなのが、Accessの画面一番下にある「ステータスバー」を利用する方法です。
専用のフォームを作らなくても、`SysCmd` メソッドを使えば、スタイリッシュなプログレスバーを簡単に表示できます。

2. 魔法のプロパティ `AbsolutePosition` とは?

今回主役として登場するのが、DAOのレコードセットが持つ `AbsolutePosition`(アソリュート・ポジション) というプロパティです。

これは、「今、レコードセットの何番目の位置(行)にいるか?」を教えてくれるカウンターです(※先頭行は `0` から始まります)。

[Record 0] -> AbsolutePosition = 0
[Record 1] -> AbsolutePosition = 1
[Record 2] -> AbsolutePosition = 2 ← 今ここ!

[Record N]

「総レコード数(`RecordCount`)」と、この「現在の位置(`AbsolutePosition`)」を組み合わせることで、「全体の何パーセントが終わったか」を正確に計算できるというわけですね。

3. 実践!進捗バー付きデータ処理コード

それでは、実際に現場でそのままコピペして使えるサンプルコードを見てみましょう。
今回は、適当な顧客テーブル(`T_顧客`)の全レコードをループ処理でスキャンし、ステータスバーに進捗を表示するシナリオです。

Sub UpdateCustomerDataWithProgress()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim totalRecords As Long
Dim currentPos As Long
Dim progressPct As Integer

‘ 処理開始時間の記録(パフォーマンス計測用)
Dim startTime As Double
startTime = Timer

Set db = CurrentDb

‘ 1. テーブルを開く(必ずダイナセットかスナップショットを使用)
Set rs = db.OpenRecordset(“T_顧客”, dbOpenSnapshot)

‘ レコードが1件もない場合のガード処理
If rs.EOF And rs.BOF Then
MsgBox “処理するデータが存在しません。”, vbInformation
GoTo Cleanup
End If

‘ 2. 総レコード数を取得するため、一旦末尾にジャンプして確認
rs.MoveLast
totalRecords = rs.RecordCount
rs.MoveFirst ‘ 先頭に戻す

‘ 3. ステータスバーの初期化(プロгреスバーモード: acSysCmdInitMeter)
‘ 引数: (アクション, バーのテキスト, 最大値)
SysCmd acSysCmdInitMeter, “データを処理しています…”, totalRecords

‘ 4. ループ処理の開始
Do While Not rs.EOF

‘ — ここに実際のデータ処理を記述します —
‘ 例として、何らかの処理をしていると仮定してスリープや処理を挟む
‘ DoEvents を入れることでOSに制御を渡し、画面の固まりを防ぎます
DoEvents
‘ —————————————-

‘ 現在の位置を取得(0から始まるため +1 する)
currentPos = rs.AbsolutePosition + 1

‘ 5. ステータスバーの更新(acSysCmdUpdateMeter)
‘ 一定間隔(例: 10件ごと)で更新すると、描画負荷による処理落ちを防げます
If currentPos Mod 10 = 0 Or currentPos = totalRecords Then
SysCmd acSysCmdUpdateMeter, currentPos
End If

‘ 次のレコードへ
rs.MoveNext
Loop

‘ 処理成功のメッセージと所要時間
MsgBox “処理が完了しました!” & vbCrLf & _
“処理件数: ” & totalRecords & “件” & vbCrLf & _
“所要時間: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation

Cleanup:
‘ 6. 終了処理(必ずステータスバーをクリアし、オブジェクトを解放する)
SysCmd acSysCmdRemoveMeter
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set db = Nothing

End Sub

4. コードの深掘りと「ここだけの注意点」

先輩エンジニアとして、このコードの重要なポイントをいくつか解説しておきますね。

① `rs.MoveLast` を忘れないで!

DAOのレコードセットを開いた直後は、正確な `RecordCount` が取得できていない場合があります(特にダイナセットの場合)。一度 `rs.MoveLast` を実行してデータベースエンジンに全件の存在を認識させるのが、正確な総数を出すための鉄則です。

② `DoEvents` の魔力

ループの中に `DoEvents` を入れています。これがあるおかげで、Windowsは「お、このアプリはちゃんと動いてるな」と認識し、進捗バーの描画やユーザーからのキャンセル操作を受け付ける余裕が生まれます。
ただし、1件ごとに `DoEvents` を呼ぶと処理スピードが落ちるため、先ほどのコードのように `Mod 10`(10件に1回)などで間引く工夫をすると、パフォーマンスと滑らかさのバランスが最高になります。

③ 終わったら必ず `SysCmd acSysCmdRemoveMeter` を呼ぶこと!

これを忘れると、VBAの処理が終わった後もAccessの画面下部に中途半端なプロгреスバーが残り続けてしまいます。お片付けはプロの基本です。

まとめ

いかがでしたでしょうか?
`AbsolutePosition` と `SysCmd` を組み合わせるだけで、ただの無機質なバッチ処理が、まるで市販のソフトウェアのような「丁寧で安心できる処理」に生まれ変わります。

  • フリーズしていると誤解させない!
  • 進捗が見えることでユーザーのイライラを解消!
  • 少しの工夫でプロっぽいシステムにランクアップ!

ここをクリアできれば、あなたのAccess VBAスキルはもう初級者を卒業し、中級エンジニアの扉を確実に叩いています。ぜひ明日の開発から取り入れてみてくださいね。それでは、また次の極限知見でお会いしましょう!

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