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

スポンサーリンク

こんにちは! 現場のシステム開発で、Access VBAと毎日格闘している先輩エンジニアです。

皆さんは、何万件ものレコードを一括処理するVBAマクロを実行したとき、画面がフリーズしたようになって「おや、ちゃんと動いているのかな…?」と不安になった経験はありませんか? 画面がピクリとも動かないまま数分間待たされるのは、ユーザーにとってなかなかのストレスですよね。

今回は、そんな「進捗が分からない不安」をキレイに解消し、プロフェッショナルなアプリケーションの佇まいを演出するテクニック「DAO.RecordsetのAbsolutePositionを活用した進捗バー(ステータスバー)の動的更新」を徹底解説します。

ここをクリアすれば、あなたの書くAccess VBAは「ただ動くプログラム」から「ユーザーに優しい洗練されたシステム」へと生まれ変わりますよ。さあ、一緒に扉を開けていきましょう!

1. なぜ「進捗(プログレス)」が見えないとダメなのか?

Accessで大量データを扱うバッチ処理(例えば、全顧客のステータス一括更新や、月次集計データの生成など)を書くとき、私たちはついつい次のようなコードを書きがちです。

‘ 【アンチパターン】これだと何が起きているか全く分からない
CurrentDb.Execute “UPDATE 顧客テーブル SET 処理済みフラグ = -1 WHERE フラグ = 0”, dbFailOnError

SQL一発で終わる処理ならこれでも良いのですが、「1件ずつ複雑な計算や外部API連携を行ってデータを加工する」ようなケースでは、どうしてもVBAのループ処理(`Do While` や `For Each`)が必要になります。

このループ処理の最中、Accessの画面は基本的に固まります。ユーザーは「固まっているのか、フリーズして強制終了すべきなのか」が判断できず、最悪の場合はタスクマネージャーから強制終了されてデータが破損する……なんて事故も起こり得ます。

だからこそ、「今、全体のうちの何%が終わっていて、あとどれくらいで終わりそうか」を可視化してあげることが、エンジニアの優しさであり腕の見せ所なのです。

2. 主役の紹介:`AbsolutePosition` とは何か?

ここで登場するのが、DAO(Data Access Objects)のレコードセットが持つ `AbsolutePosition` というプロパティです。

言葉の通り、レコードセット内での「現在のレコードの絶対位置(何番目にいるか)」を0から始まるインデックスで返してくれます。

  • 先頭のレコード: `0`
  • 2番目のレコード: `1`
  • 最後のレコード: `RecordCount – 1`

「あれ? わざわざ自分でカウンタ変数(`i = i + 1`)を用意しちゃダメなの?」と思ったそこのあなた、素晴らしい着眼点です。
もちろん自前でカウンタを用意しても動きますが、DAOの `AbsolutePosition` を使えば、エンジン側が管理している位置情報をダイレクトに取得できるため、コードがスッキリするだけでなく、余計な変数管理のバグを防ぐことができます。

3. 実践!ステータスバーを動的にジャックするコード

それでは、実際にAccessの画面下部にあるステータスバーを活用して、進捗率をリアルタイムに表示するサンプルコードを見てみましょう。

今回は、ダミーの顧客テーブル(`T_顧客`)をループし、1件ずつ何らかの処理を行うシナリオを想定しています。

Public Sub RunWithProgress()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim totalRecords As Long
Dim currentPos As Long
Dim progressPercent As Integer
Dim startTime As Double

startTime = Timer ‘ 処理時間計測用(おまけ)

Set db = CurrentDb
‘ パフォーマンスとメモリ効率を意識し、ダイナセット型で開く
Set rs = db.OpenRecordset(“SELECT FROM T_顧客 WHERE 処理済み = 0”, dbOpenDynaset)

‘ 対象データが0件なら即座に抜ける
If rs.EOF Then
MsgBox “処理対象のデータはありません。”, vbInformation, “お知らせ”
GoTo Cleanup
End If

‘ 【重要】RecordCountを正確に取得するために最後までダミー移動する
rs.MoveLast
totalRecords = rs.RecordCount
rs.MoveFirst

‘ ステータスバーに初期メッセージを表示
SysCmd acSysCmdSetStatus, “データ処理を開始します… (0/” & totalRecords & “件)”

‘ メインのループ処理
Do While Not rs.EOF
‘ ————————————————–
‘ ここに実際のデータ処理(更新や計算など)を書く
‘ ————————————————–
rs.Edit
rs!処理済み = True
rs.Update
‘ ————————————————–

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

‘ 進捗率(%)を計算
progressPercent = CInt((currentPos / totalRecords) 100)

‘ 一定間隔(または全件)でステータスバーを更新
‘ ※毎回SysCmdを呼ぶと描画負荷になるため、数件に1回にするのもテクニックですが、
‘  まずはシンプルに毎回更新するコードで解説します。
SysCmd acSysCmdSetStatus, “処理中: ” & progressPercent & “% 完了 (” & currentPos & ” / ” & totalRecords & “件)”

‘ アクセスが画面を描画する余裕を与える(フリーズ防止の肝)
DoEvents

rs.MoveNext
Loop

‘ 終了メッセージ
SysCmd acSysCmdClearStatus
MsgBox “すべての処理が完了しました! (処理時間: ” & Format(Timer – startTime, “0.0”) & “秒)”, vbInformation, “完了”

Cleanup:
‘ オブジェクトの解放(メモリリークを防ぐプロの鉄則)
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set db = Nothing
End Sub

4. コードの重要ポイントを深掘り解説!

初心者の方が「おっ」と躓きやすいポイントや、プログラミングの本質的なコツをいくつか解説しておきますね。

① `rs.MoveLast` の意味と罠

DAOのレコードセットを開いた直後、`RecordCount` プロパティは「正確な総数」を返していないことがあります(特にダイナセットやスナップショットの場合、実際に最後のレコードまでアクセスしないと総数が確定しない仕様になっています)。
そのため、ループを回す前に必ず `rs.MoveLast` を実行してデータベースエンジンに全件をロードさせ、その後に `rs.MoveFirst` で先頭に戻すのが鉄則です。これを忘れると、進捗率の分母がおかしくなり、計算エラーや予期せぬ挙動を引き起こします。

② `DoEvents` という名の魔法の呪文

VBAが重いループを回しているとき、WindowsはAccessに対して「おい、仕事中だから他のウィンドウの描画とか受け付けないからね」とCPUを占有させます。
ここに `DoEvents` を挟むことで、VBAは一時的にOSに制御を渡し、「今のうちに画面の表示(ステータスバーの更新など)を更新していいよ!」と伝えます。これがあるおかげで、画面がフリーズせずに進捗バーやステータスがグリグリ動くようになるのです。

③ オブジェクトの解放(メモリ管理)

コードの最後にある `Cleanup:` ラベルの部分です。
`Set rs = Nothing` や `Set db = Nothing` をサボる初心者が非常に多いのですが、これをやらないとAccessのメモリ内にゴミ(リソース)が残り続け、長時間の運用でAccessが突然落ちる(メモリリーク)原因になります。プロのエンジニアは「開いたものは必ず閉じる・解放する」を美学としています。

5. さらに高みを目指すあなたへ:ステータスバーの限界とプログレスバー

今回ご紹介した `SysCmd acSysCmdSetStatus` を使ったステータスバーへの文字表示は、Access標準機能だけで実装でき、非常に手軽で実用的です。

しかし、「もっと視覚的に、緑色のバーがグデーッと伸びていくようなプログレスバーをフォーム上に作たい!」という場合は、ユーザーフォーム(UserForm)を新規作成し、その中に「ラベルコントロール」を配置して、ラベルの `Width`(幅)を `progressPercent` に応じてピクセル単位で変化させるというテクニックを使います。

基本の考え方は今回の `AbsolutePosition` を使った割合計算と全く同じです。ぜひ、ご自身のフォームでも応用してみてください。

まとめ

今回は `DAO.Recordset.AbsolutePosition` を使った進捗表示のテクニックについて、現場の知見を交えて解説しました。

  • 進捗の可視化は、ユーザーの不安を消し、システムの信頼性を劇的に高める。
  • `AbsolutePosition` を使えば、スマートに現在のレコード位置が取得できる。
  • `MoveLast` → `MoveFirst` のお作法を忘れずに。
  • `DoEvents` で画面のフリーズを防ぎ、最後は必ずオブジェクトを解放する。

ここをマスターすれば、もう「動いているのか分からない恐怖」に怯える必要はありません。ぜひ次の開発案件から取り入れて、周囲をうならせる快適なツールを作ってみてくださいね。

あなたのAccessライフが、より快適で知的で楽しいものになりますように! 次回の記事もお楽しみに。

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