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

スポンサーリンク

こんにちは!Access VBAの世界へようこそ。
日々、膨大なデータ処理やフォームの制御に奮闘されていることと思います。

「ボタンを押すと処理が始まるけれど、終わるまで画面がフリーズして他の操作が一切できない……」
「裏側でこっそりデータの自動保存やメールチェックをしておきたいのに、VBAのシングルスレッドのせいでメイン画面が固まってしまう……」

そんな悩みに直面したことはありませんか?
今回は、Accessが持つ「TimerInterval(タイマー間隔)」「OnTimer(タイマー時)」という強力なイベントプロパティを駆使して、まるで裏で別プログラムが動いているかのような「擬似マルチスレッド処理」を実現する方法を伝授します。

ここをクリアすれば、あなたの作るAccessアプリは「カクカクして重いレガシーなツール」から、「キビキビ動くモダンなシステム」へと生まれ変わります。さあ、一緒に本質をマスターしていきましょう!

1. なぜAccessは「固まる」のか?(シングルスレッドの宿命)

まず、敵を知ることから始めましょう。
Access VBAは、基本「シングルスレッド」で動作します。つまり、ひとつの処理(例えば重たい集計クエリの実行や、大量のレコード更新)が走り出すと、VBAはその処理が完了するまで他のことに頭を使う余裕がなくなります。これが、画面が真っ白になったり「応答なし」になったりする正体です。

マルチスレッド(同時に複数の処理を動かすこと)ができれば楽なのですが、AccessのVBA単体では真のマルチスレッドは使えません。

そこで登場するのが、「時間を細切れにして、超高速で仕事を割り込む」という職人技、すなわちタイマーイベントによる擬似マルチスレッドです。

2. 秘密兵器:TimerInterval と OnTimer の仕組み

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

  • `TimerInterval` (タイマー間隔)
  • ミリ秒単位で時間を設定します。例えば `1000` と設定すると、1秒(1000ミリ秒)ごとにイベントが発火します。
  • `0` を設定するとタイマーは停止します。
  • `OnTimer` (タイマー時)
  • `TimerInterval` で設定した時間が経過するたびに、自動的に呼び出されるイベントプロシージャです。

🧠 脳内イメージ:コンベアベルトの比喩

想像してください。あなたが工場(Access)のラインで作業をしています。
通常のVBAは、「一つの巨大な家具を作り終えるまで、他の来客対応もトイレも一切しない」という頑固な職人です。

しかし、タイマーを使うとどうでしょう?
「0.1秒(100ミリ秒)ごとに作業の手を止め、未処理の注文書が溜まっていないかチラッと確認する。溜まっていれば1件だけ処理して、また次の作業に戻る」
これを人間には認知できないほどの超高速で行うことで、あたかも裏で別の仕事が同時に進んでいるように見せるわけです。これがバックグラウンド処理の正体です。

3. 【実践】バックグラウンドで非同期タスクを回すコード例

それでは、実際に手を動かしてみましょう。
今回は、「メイン画面を操作しながら、裏で5秒おきに未送信データのチェック(擬似的なバックグラウンド処理)を行う」フォームを作ります。

手順1:フォームの準備

1. 適当なフォームをデザインビューで開きます。
2. プロパティシートを開き、以下の設定を行います。

  • タイマー間隔 (TimerInterval): `1000` (1秒ごとにチェック)
  • タイマー時 (OnTimer): `[イベント プロシージャ]` を選択し、右側の `…` ボタンをクリックしてVBAエディタを開きます。

手順2:VBAコードの実装

VBAエディタが開いたら、以下のコードを記述してください。

Option Compare Database
Option Explicit

‘ — バックグラウンド処理の状態を管理する変数 —
Private m_IsProcessing As Boolean

Private Sub Form_Timer()
‘ —————————————————————-
‘ 【重要】多重起動の防止(Re-entrancy Guard)
‘ 処理が重すぎて1秒以内に終わらなかった場合、前の処理が終わらないうちに
‘ 次のTimerイベントが発火してカオスになるのを防ぎます。
‘ —————————————————————-
If m_IsProcessing Then Exit Sub

‘ 処理中フラグを立てる
m_IsProcessing = True

On Error GoTo ErrorHandler

‘ — ここからバックグラウンドで実行したい処理を記述 —
‘ 例:ステータスバーに裏で動いていることを表示
Me.LabelStatus.Caption = “バックグラウンドでデータを巡回中…” & Format(Now, “hh:nn:ss”)

‘ 【実務のヒント】
‘ ここで重い一括処理をすべてやると画面が固まります。
‘ 「未処理のレコードを1件だけ取得して処理する」といった
‘ チャンク(分割)処理にするのが、プロの技です。
Call ExecuteBackgroundJob_Chunk()

ErrorHandler:
If Err.Number <> 0 Then
‘ エラーでアプリが停止しないよう、ログに残してスルーする等の配慮を
Debug.Print “Timer Error: ” & Err.Description
End If

‘ 処理中フラグを下ろす
m_IsProcessing = False
End Sub

Private Sub ExecuteBackgroundJob_Chunk()
‘ ここに実際の軽量化されたバックグラウンド処理を書きます
‘ 例として、デバッグウィンドウにメッセージを出力
Debug.Print “【BG処理】未送信データの有無をチェックしました: ” & Now

‘ ※ここに「DLookup」や「CurrentDb.Execute」などを用いた
‘  1件ずつのデータ処理を組み込むと非常に安定します。
End Sub

Private Sub Form_Load()
‘ フォームロード時の初期化
m_IsProcessing = False
Me.LabelStatus.Caption = “システム稼働中(裏で監視中)”
End Sub

4. 現場で絶対にハマる!陥りやすい罠と回避策

このタイマー処理、非常に便利な反面、Accessの裏側を知らないと痛い目を見る「落とし穴」があります。プロの現場で生き残るための知見をいくつか共有しておきます。

罠1:タイマーイベントの中での「重すぎる処理」

`TimerInterval`を短い時間(例: `100` ミリ秒)に設定しているにもかかわらず、その中で何万件ものレコードをループで回すような重い処理を書くと、結局メインスレッドが占有され、フォームは完全にフリーズします。

  • 対策:バックグラウンドで行う処理は必ず「1回につき1レコードだけ処理して抜ける(チャンク分割)」ように設計しましょう。

罠2:エラーハンドリングの欠如による「サイレントキル」

タイマーイベント内で未処理のエラー(例えば、ネットワークが一時的に切れてテーブル更新に失敗した等)が発生すると、VBAのエラーメッセージが出たままタイマーが暴走するか、最悪の場合はAccess自体が強制終了します。

  • 対策:必ず `On Error GoTo ErrorHandler` を仕込み、エラー時はログに記録して処理を安全にスキップ(`m_IsProcessing = False` を確実に通過させる)構造にしてください。

罠3: オブジェクトのライフサイクルへの配慮

タイマーが動いている最中にユーザーがフォームを閉じようとしたり、別の画面に移動したりすると、メモリ上に存在しないコントロールを操作しようとしてエラーになります。

  • 対策:フォームを閉じる際(`Unload`イベントなど)には、念のため `Me.TimerInterval = 0` を明示的に実行してタイマーを必ず停止させる癖をつけましょう。

まとめ

いかがでしたでしょうか?
今回は、Accessの制限を逆手にとり、`TimerInterval` と `OnTimer` を使ってバックグラウンドの擬似マルチスレッド処理を実現する方法を解説しました。

  • シングルスレッドの制約は「時間を細切れにする(チャンク処理)」で突破する。
  • 多重起動を防ぐためのフラグ管理(`m_IsProcessing`)を忘れない。
  • エラーハンドリングとタイマーの停止(ライフサイクル管理)を徹底する。

ここをクリアすれば、あなたも単なる「コードのコピペ職人」から、「堅牢なアーキテクチャを設計できるエンジニア」へ一歩ステップアップです。
ぜひ、あなたの開発するAccessアプリにこのテクニックを取り入れ、サクサク動く快適なシステムを実現してみてくださいね。応援しています!

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