こんにちは!Access VBAの開発現場で、日夜データベースと格闘お疲れ様です。
大量のデータを処理するループを回すとき、`Application.Echo False` を使って画面の描画をピタッと止めると、処理速度が劇的に跳ね上がりますよね。「よし、これで爆速だ!」と満足してテストを走らせている最中……あろうことか、予期せぬエラーでコードが突如としてストップ!
……気づけば、画面がフリーズしたかのように一切更新されず、Accessを強制終了する羽目になった。そんな冷や汗をかくような恐怖体験、あなたも一度や二度ではないはずです。
今回は、そんな悲劇を「絶対に」防ぐための極意――クラスモジュールのライフサイクルを利用した、安全かつエレガントな画面描画制御の仕組みを伝授します。ここをクリアすれば、あなたの書くAccess VBAの信頼性はプロの領域へと一気に飛躍しますよ。さあ、一緒に扉を開けましょう!
—
なぜ `Application.Echo` は罠だらけなのか?
Accessは、フォームの再描画やコントロールの更新を行うたびに裏で膨大なリソースを消費しています。そのため、数千件のレコードをゴリゴリ処理するマクロやVBAでは、以下のように画面描画を一度オフにするのが定石です。
‘ 【危険なアンチパターン】
Application.Echo False ‘ 画面描画を停止
‘ — 大量のデータ処理(ここでエラーが起きたら…?) —
Call 危険なデータ処理()
Application.Echo True ‘ 画面描画を復帰
一見、何の問題もないように見えますよね。しかし、プログラミングの鉄則は「エラーはいついかなる時でも発生しうる」ということです。
もし、`危険なデータ処理()` の中で型変換エラーや実行時エラーが発生したらどうなるでしょうか? VBAの実行はそこで中断され、その下にある `Application.Echo True` にたどり着くことは永遠にありません。結果として、Accessの画面は描画が停止したまま凍結(エコーオフのまま)。ユーザーは「バグった!」とパニックになり、タスクマネージャーで強制終了するしかなくなるのです。
—
救世主はクラスモジュールの「Terminateイベント」
「じゃあ、エラー処理(`On Error GoTo`)を毎回書けばいいじゃないか」と思いますよね。もちろんそれも一つの手ですが、すべてのプロシージャに同じエラー処理を書くのは冗長ですし、何より書き忘れるリスクが残ります。
ここで、オブジェクト指向の隠れた名機能――クラスモジュールの「Terminate(終了)イベント」を使います。
Access VBAのクラスには、インスタンスがメモリから消滅する(スコープから外れる)瞬間、自動的に実行される `Class_Terminate` というイベントが存在します。「このクラスが存在している間だけ画面を止め、クラスが消滅するとき(=プロシージャを抜けるとき)には、エラーの有無に関わらず強制的に画面を復帰させる」。この仕組みを作れば、エラーに怯える必要は一切なくなります。
—
実装:汎用エコー制御クラスを作ろう!
それでは、実際に現場でそのままコピペして使える「画面描画制御クラス」を実装してみましょう。
手順1:クラスモジュールの作成
VBE(Visual Basic Editor)を開き、メニューの [挿入] > [クラス モジュール] をクリックします。
新しくできたクラスモジュールのプロパティウィンドウで、名前を `clsScreenLock` に変更してください。
そして、以下のコードをそのまま貼り付けます。
‘ =================================================================
‘ クラス名: clsScreenLock
‘ 概要: 画面描画(Echo)とマウスポインタを安全に制御するクラス
‘ =================================================================
Option Explicit
‘ クラスが生成された(インスタンス化された)ときに走るイベント
Private Sub Class_Initialize()
‘ 画面の描画を停止してパフォーマンスを向上させる
Application.Echo False
‘ ついでにカーソルを砂時計(処理中)にしてあげると親切です
DoCmd.Hourglass True
End Sub
‘ クラスが破棄される(メモリから消える)ときに「必ず」走るイベント
Private Sub Class_Terminate()
‘ どんなに無様なエラーで落ちようとも、ここが必ず実行されます
On Error Resume Next
DoCmd.Hourglass False
Application.Echo True
On Error GoTo 0
End Sub
たったこれだけです!たったこれだけのコードが、あなたのAccessアプリを鉄壁の守りへと変えてくれます。
—
手順2:標準モジュールからの呼び出し方
作ったクラスを実際に標準モジュールやフォームのコードから使ってみましょう。使い方は驚くほどシンプルです。
‘ =================================================================
‘ プロシージャ例:安全なデータ一括処理
‘ =================================================================
Sub RunSafeBatchProcess()
‘ 【重要】クラスのインスタンスを生成した瞬間、Echo Falseが発動します
Dim screenLock As clsScreenLock
Set screenLock = New clsScreenLock
On Error GoTo ErrorHandler
‘ — ここから通常の重い処理を記述 —
Debug.Print “重い処理を開始します…”
‘ わざとエラーを起こしてみるテスト(コメントアウトを外すとエラーが発生します)
‘ Err.Raise 9999, , “予期せぬエラー発生!”
‘ 擬似的な重いループ処理
Dim i As Long
For i = 1 to 1000000
‘ 何らかのデータ処理
Next i
Debug.Print “処理が正常に完了しました。”
NormalExit:
‘ 【ポイント】ここで変数を明示的に破棄、またはプロシージャを抜けることで
‘ clsScreenLockの Class_Terminate が走り、画面が自動で復帰します。
Set screenLock = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しましたが、画面は正常に復帰します。” & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “システムエラー”
Resume NormalExit
End Sub
このコードの何が凄いのか?
1. エラーが起きても確実に画面が戻る
`Err.Raise` で強制的にエラーを起こそうが、予期せぬゼロ除算エラーが起きようが、VBAの実行が `ErrorHandler` を経て `NormalExit` に向かう際、あるいはプロシージャのスコープを抜ける際に、`screenLock` 変数が破棄されます。その瞬間、`Class_Terminate` が作動し、確実に `Application.Echo True` が実行されます。
2. コードが美しく、メンテナンス性が高い
プロシージャのあちこちに `Application.Echo True` を書き散らす必要がなくなります。書き忘れによる「画面フリーズ事故」が物理的に起こらなくなるため、デバッグのストレスから完全に解放されます。
—
レイヤの高いエンジニアほど、「エラーが起きたときの後始末」を美しく設計するもの。「ここをこうしておけば、万が一の時もシステムが崩壊しない」という安心感の積み重ねが、プロ品質のAccessアプリケーションを形作ります。
ぜひ、あなたのプロジェクトにもこの `clsScreenLock` を導入してみてください。Access VBAのコーディングが、一段と楽しく、スマートになりますよ!
