【入門編】【上級】フォームの「TimerInterval」と「OnTimer」で実現する、バックグラウンドでの擬似マルチスレッド処理 – Access VBA解析バイブル

スポンサーリンク

こんにちは!Accessのフォームを作っていて、こんな経験はありませんか?

「重い集計処理や、大量データのインポートを実行した途端、画面が真っ白になって固まった……」
「『応答なし』になって、Accessごと強制終了するしかない……」

もしあなたが今、この壁にぶつかっているなら、おめでとうございます。それはあなたがAccess VBAの「次のステージ」に進むタイミングが来た証拠です。

今回は、Accessのシングルスレッドという宿命を鮮やかに回避し、まるで裏側で別の作業が動いているかのようにUI(画面)をフリーズさせない「TimerIntervalとOnTimerによる擬似マルチスレッド処理」の極意を授けましょう。

ここをクリアすれば、あなたの作るAccessアプリは、プロが組んだ洗練されたシステムへと生まれ変わります。一緒に一歩ずつ、本質を紐解いていきましょう!

1. なぜAccessは重い処理でフリーズするのか?

まず、敵を知ることから始めましょう。
Access VBAは「シングルスレッド(=同時に1つのことしかできない)」で動いています。

人間で例えるなら、1人の作業員が「画面の監視(ユーザーからのクリック受付)」と「巨大な荷物の運搬(重いデータ処理)」を1人で兼務している状態です。作業員が重い荷物を抱えた瞬間、周囲の声(クリックやキー入力)が一切聞こえなくなります。これが「フリーズ(応答なし)」の正体です。

解決の鍵:小分けにして「ながら作業」をする

では、どうすればいいのでしょうか?
答えは簡単です。重い荷物を一度に運ぶのではなく、「10個ずつに小分けにして、少し運んだら周囲の様子を見る」という動作を猛スピードで繰り返せばいいのです。

これをAccess VBAで実現するのが、フォームの `TimerInterval`(タイマー間隔)`OnTimer`(タイマー時) イベントです。

2. 魔法のタイマープロパティの仕組み

フォームには、一定時間ごとに自動でイベントを発生させる機能が備わっています。

  • `TimerInterval`: タイマーを動かす間隔を「ミリ秒」で指定します(例: `1000` なら1秒)。
  • `OnTimer`: `TimerInterval` で指定した時間が来るたびに、自動的に呼び出されるイベントプロシージャです。

通常の開発では「時計の表示」や「定期的なデータの自動保存」に使われますが、これを「重い処理のコマ送りエンジン」として使います。これが、今回お伝えする「擬似マルチスレッド」の核心です。

3. 【実践】画面をフリーズさせないバックグラウンド処理の実装

百聞は一見にしかず。実際にコードを書いてみましょう。

今回は、「10万件のダミーデータをテーブルに登録する」という重い処理を、画面をフリーズさせずに裏で少しずつ実行するサンプルを作成します。

ステップ1:準備するパーツ

1. 適当なフォームを1つ作成し、名前を `frmTaskRunner` とします。
2. フォームにボタンを1つ配置し、名前を `cmdStart` とします。
3. フォームにプログレスバーの代わりとして、テキストボックスを1つ配置し、名前を `txtStatus` とします。

ステップ2:VBAコードの記述

フォームのコードモジュールを開き、以下のコードをそのまま貼り付けてください。

Option Compare Database
Option Explicit

‘ — 処理の状態を保持するモジュールレベル変数 —
Private m_CurrentIndex As Long ‘ 現在何件目まで処理したか
Private Const BATCH_SIZE As Long = 500 ‘ 1回あたりに処理する件数
Private Const TOTAL_RECORDS As Long = 10000 -> 実際は10000件等に調整
Private Const TOTAL_RECORDS_REAL As Long = 100000 ‘ 総処理件数

Private Sub cmdStart_Click()
‘ 【初期化フェーズ】
m_CurrentIndex = 0
Me.txtStatus.Value = “処理を開始します…”

‘ ボタンを二重押しできないように無効化
Me.cmdStart.Enabled = False

‘ タイマーを起動! (例: 50ミリ秒ごとにOnTimerイベントを発生させる)
Me.TimerInterval = 50

MsgBox “バックグラウンド処理を開始しました!” & vbCrLf & _
“処理中もフォームの移動や他の操作が可能です。”, vbInformation
End Sub

Private Sub Form_Timer()
On Error GoTo ErrorHandler

Dim i As Long
Dim targetCount As Long

‘ 今回のバッチで処理する終了位置を計算
targetCount = m_CurrentIndex + BATCH_SIZE
If targetCount > TOTAL_RECORDS_REAL Then
targetCount = TOTAL_RECORDS_REAL
End If

‘ 【チャンク(小分け)処理の実行】
‘ ここでは擬似的にループを回しますが、実際はトランザクションやレコードセットの操作を行います
For i = m_CurrentIndex + 1 To targetCount
‘ 例:何らかの重い処理(今回はダンプ代わりにデバッグ出力)
‘ Debug.Print “Processing record: ” & i
Next i

‘ 現在地を更新
m_CurrentIndex = targetCount

‘ 画面の進捗を表示(これでUIが生きていることがユーザーに伝わります)
Me.txtStatus.Value = “処理中… ” & m_CurrentIndex & ” / ” & TOTAL_RECORDS_REAL & ” 件完了”

‘ 【終了判定フェーズ】
If m_CurrentIndex >= TOTAL_RECORDS_REAL Then
‘ タイマーを停止(0を設定すると停止します)
Me.TimerInterval = 0

‘ ボタンを元に戻す
Me.cmdStart.Enabled = True

Me.txtStatus.Value = “すべての処理が完了しました!”
MsgBox “バックグラウンド処理が正常に完了しました。”, vbInformation
End If

Exit Sub

ErrorHandler:
‘ エラーが発生した場合もタイマーを止めないと無限ループ化するので注意!
Me.TimerInterval = 0
Me.cmdStart.Enabled = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub

4. コードの解説と「知る人ぞ知る」注意点

このコードの美しいところは、`For` ループを一気に回さず、`TimerInterval = 50` によって「50ミリ秒ごとに500件ずつ、細切れに処理を進めている」点にあります。

これにより、Accessは500件処理するたびに「一息つく(イベントキューを処理する)」ことができるため、ユーザーがフォームを動かしたり、別のボタンを押したりすることが可能になるのです。まさに擬似的なマルチスレッドですね。

⚠️ ここで絶対に押さえておかなければならないプロの鉄則

1. エラー時のタイマー停止 (`Me.TimerInterval = 0`)
もし `OnTimer` イベントの中でエラーが発生した際、エラー処理(ErrorHandler)でタイマーを止め忘れると、エラーダイアログが出たまま裏でタイマーが暴走し続け、Accessがハングアップします。エラーハンドラ内でのタイマー停止は絶対のルールです。
2. モジュールレベル変数で状態を記憶する
通常のプロシージャであれば、終われば変数は消滅しますが、タイマー処理は「前回どこまで進んだか」を覚えておく必要があります。そのため、`m_CurrentIndex` のようなモジュールレベル変数(Private変数)が不可欠になります。
3. TimerIntervalの頻度設定に注意
値を小さくしすぎ(例: `1` や `10`)すぎると、Accessがタイマー処理の対応に追われてかえってパフォーマンスが落ちます。人間の目でスムーズと感じる `50` ~ `100` ミリ秒 辺りが黄金比です。

まとめ:Access VBAの限界を突破しよう

いかがでしたか?
「Accessだから重い処理でフリーズするのは仕方ない」と諦めていた機能も、今回紹介した `TimerInterval` と `OnTimer` を使ったコマ送り処理(チャンク処理)を導入すれば、見違えるほど快適でプロフェッショナルな挙動に生まれ変わります。

ここをクリアできたあなたなら、もうマクロの記録や初歩的なVBAの記述からは完全に卒業です。ぜひ実際の業務アプリで試して、その快適な動作を体感してみてください。

あなたのAccess開発ライフが、より一層知的に、そしてスマートになることを応援しています!

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