こんにちは!Access VBAでの開発、日々お疲れ様です。
マクロの記録から一歩踏み出し、自分の手でロジックを組み立てる面白さを感じ始めている頃ではないでしょうか。
今回は、実務で絶対に直面する「重いデータ処理の待たされ問題」をスマートに解決するテクニックをお伝えします。
何万件ものレコードを一括処理するとき、画面が固まったようになり、「いま何件目?本当に動いているの?」と不安になった経験はありませんか?ユーザーに無駄なストレスを与えず、プロフェッショナルなアプリケーション感を演出するために不可欠なのが「プログレスバー(進捗表示)」です。
今回はDAOの `AbsolutePosition` という強力なプロパティを使って、進捗バーを優雅に動かす極意を伝授します。ここをクリアすれば、Access VBAの基本と「動く仕組み」の理解がグッと深まりますよ。一緒にマスターしていきましょう!
—
なぜ「進捗バー」の制御でつまずくのか?
VBAでループ処理を書くとき、私たちはよく `For…Next` や `Do…Loop` を使います。
例えば、10,000件のデータを処理する場合、単純にループを回すだけでは「全体に対して今何%終わっているのか」をコード自身が把握できません。
「レコードの総数(分母)」と「現在の処理位置(分子)」がリアルタイムでわかれば進捗率は計算できますが、毎回 `DCount` 関数などで現在地を数えにいっては、それだけで処理が何倍にも重くなってしまいます。
そこで登場するのが、DAO(Data Access Objects)の `AbsolutePosition` です。
AbsolutePositionとは?
`Recordset` オブジェクトが現在どこを指しているのか(何番目のレコードにいるのか)を教えてくれるプロパティです。
ただし、これには一つだけ致命的な注意点があります。
> ⚠️ 注意:AbsolutePositionは「0始まり」
> 最初のレコードは `0`、2番目は `1` になります。そのため、件数を計算する際には「+1」する配慮が必要です。また、レコードセットの種類(ダイナセットやスナップショットなど)によっては正しく機能しない場合があるため、前方スクロールのみ(dbOpenForwardOnly)の軽量なレコードセットで使うのがプロの鉄則です。
—
実践!ステータスバーとフォームを連動させるコード
今回は、Access標準の機能であるステータスバー(画面一番下のバー)と、フォーム上のプログレスバーを同時に動かす実践的なコードを書きました。
そのままコピペして、お手元のボタンイベントなどに貼り付けて試してみてください。
Sub UpdateProgressDemo()
Dim db As DAO.Database
Dim rs As DAO.Recordset
String strSQL As String
Dim totalRecords As Long
Dim currentPos As Long
Dim progressPct As Integer
On Error GoTo ErrorHandler
‘ 1. 処理対象のデータを取得(軽量なForwardOnlyで開くのが極意)
Set db = CurrentDb
strSQL = “SELECT FROM T_顧客マスター WHERE 処理済み = False;”
Set rs = db.OpenRecordset(strSQL, dbOpenSnapshot, dbOpenForwardOnly)
‘ 2. レコードが0件なら即座に抜ける
If rs.EOF Then
MsgBox “処理対象のデータはありません。”, vbInformation
GoTo Cleanup
End If
‘ 3. 総レコード数を取得する(※注意:一度最後まで移動して正確な件数を確定させる)
rs.MoveLast
totalRecords = rs.RecordCount
rs.MoveFirst ‘ 先頭に戻して処理スタート
‘ ステータスバーに初期メッセージを表示
SysCmd acSysCmdInitMeter, “データを処理しています…”, totalRecords
‘ 4. ループ処理の開始
Do While Not rs.EOF
‘ — ここに実際の重い処理を書く(例:フラグの書き換えなど)—
‘ db.Execute “UPDATE …”, dbFailOnError 等の代替、あるいはフィールド操作
‘ rs.Edit
‘ rs!処理済み = True
‘ rs.Update
‘ —————————————————————–
‘ 5. 現在位置(AbsolutePosition)の取得と進捗の反映
currentPos = rs.AbsolutePosition + 1 ‘ 0始まりなので+1する
‘ ステータスバーの更新
SysCmd acSysCmdUpdateMeter, currentPos
‘ フォーム上のラベル等に文字で進捗を出す場合
‘ Me.lblStatus.Caption = currentPos & ” / ” & totalRecords & ” 件完了”
‘ 画面の描画をフリーズさせないための重要なおまじない
DoEvents
rs.MoveNext
Loop
‘ 6. 完了メッセージ
SysCmd acSysCmdRemoveMeter
MsgBox “全 ” & totalRecords & ” 件の処理が正常に完了しました!”, vbInformation
Cleanup:
‘ 7. オブジェクトの解放(メモリリークを防ぐプロの作法)
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
‘ エラーハンドリング
SysCmd acSysCmdRemoveMeter
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume Cleanup
End Sub
—
コードの注目ポイント(エンジニアのこだわり)
初学者のうちは「動けばいいや」となりがちですが、実務の現場では以下の3つが極めて重要です。
1. `DoEvents` の魔法
VBAは処理に没頭すると、Windowsに対して「画面を描画する余裕」を与えなくなります。その結果、画面が真っ白に固まります。ループの中に `DoEvents` を挟むことで、OSに「いま動いてるよ、画面を再描画してね」と制御を明け渡し、ユーザーが「フリーズした(強制終了しよう)」と勘違いするのを防ぎます。
2. `SysCmd` 関数の活用
わざわざ専用のプログレスバーフォームを作らなくても、Access標準の `SysCmd` を使えば、画面一番下のステータスバーに綺麗なインジケータ(緑色のバー)を出すことができます。手軽かつスマートです。
3. 徹底的なメモリ解放
`Set rs = Nothing` や `Set db = Nothing` を怠ると、見えないところでメモリが圧迫され、Accessが不安定になる原因を作ります。「使ったものは綺麗に片付ける」を習慣にしましょう。
—
ここをクリアすれば、Access VBAの基本はバッチリ!
いかがでしょうか?
`AbsolutePosition` という少しマニアックなプロパティの性質を知るだけで、アプリケーションの「ユーザー体験(UX)」劇的に向上させることができます。
「動くだけのコード」から、「使う人に優しいコード」へ。
この視点を持てたなら、あなたのVBAスキルはもう初学者を卒業し、立派な開発者の領域に入っています。
エラーが出たり、もっとこうしたいという疑問があれば、いつでも気軽に相談してくださいね。あなたのAccess開発ライフを、これからも応援しています!
