Microsoft Accessでフォームを作っていると、「この処理、どのイベントに書くのが正解なんだろう?」と迷った経験はありませんか?
“開くとき”や“閉じるとき”に複数のイベントが発生しますが、その実行順を正確に把握できているでしょうか。
Form_Open、Form_Load、Form_Current、Form_Activate……
イベントの種類は多いのに、それぞれいつ・どんな順番で実行されているのかは意外と意識しないまま使っている方も多いと思います。
その結果、次のような問題が起こりがちです。
- 想定より早く処理が走ってエラーになる
- なぜか処理が二重に実行される
- 開いた直後と、フォーカス移動時で挙動が変わる
といった「理由の分からない挙動」に悩まされがちです。
特に「Form_OpenとForm_Loadの違いが分からない」「Form_Currentに書いたら二重実行された」といった悩みは、イベントの発生順を正しく理解していないことが原因であるケースがほとんどです。
この記事では、Accessフォームを開いてから閉じるまでに発生するイベントを、実際に検証した結果をもとに時系列で整理します。
さらに、使用可能なオブジェクトがある場合/ない場合で何が変わるのかについても比較し、「どのイベントに処理を書くべきか」を判断しやすくなることを目的としています。
フォームのイベント処理で一度でも首をかしげたことがある方は、ぜひ参考にしてみてください。
この記事で分かること
- Accessフォームのイベントが発生する正確な順番
- Form_Open / Load / Current / Activate の役割の違い
- オブジェクト有無で何が変わるのか
- 処理を書くときに避けた方がいいイベント
※ 本記事は、Accessフォームのイベントを一通り使ったことはあるが、「どこに何を書くべきか」で迷った経験がある方向けの内容です。
※ 本検証はシングルフォームを前提としています。サブフォームや連続フォームでは結果が異なる可能性があります。
調査の方法
ここでは「イベントが実際にどの順番で動いているのか」を推測ではなくログとして確認するための方法を紹介します。
調査の方法としては、フォーム(F_MAIN)とテーブル(T_処理)を準備し、各イベントの発生時に処理名と処理の対象をテーブルに追加クエリ(Q_追加)で追加する方法で行いました。
テーブルのフィールドは以下のように設定
- id 【長整数型オートナンバー】
- 処理名 【テキスト型】
- 対象 【テキスト型】
追加クエリ(Q_追加)は以下のSQLで実施
INSERT INTO T_処理 ( 処理名, 対象 ) SELECT iddataf() AS 処理名, TaisyouF() AS 対象;
上記SQLではマーカーの自作関数を2つ利用しています。
上記関数も含めた作成モジュール全文は以下の通り
Option Compare Database
Public iddata As String
Public taisyou As String
Private Declare Sub Sleep Lib "kernel32" (ByVal sleep_milli_second As Long)
Function IDdataF()
IDdataF = iddata
End Function
Function TaisyouF()
TaisyouF = taisyou
End Function
Sub SyoriID(strIDdata As String, strTaisyou As String)
iddata = strIDdata
taisyou = strTaisyou
DoCmd.SetWarnings False
DoCmd.OpenQuery "Q_追加"
DoCmd.SetWarnings True
Sleep 100
End Sub
SyoriID関数をフォームの各イベントに記述することで、実行されるイベントの順番をT_処理保管する形となります。
また、Sleep 100で処理を100ミリ秒待たせて順番の入れ替わりがないように設定しています。
(おそらく同期処理と思われるので不要だとは思いますが念のため)
フォームのイベントの記述は以下の通り。
Private Sub Form_Open(Cancel As Integer)
Call SyoriID("開く時", "フォーム")
End Sub
開いて閉じるまでに発生するイベント
では、前述の処理を用いて検証した結果を見ていきましょう。
フォームの開き方はナビゲーションウィンドウから「F_MAIN」をダブルクリックで開く。
タブで表示されているフォームのxボタンで閉じる方法で閉じる。
という方法を取っています。
Accessフォームではフォーム上のボタンを利用して閉じることが可能ですが、オブジェクトの影響を極力避けるため、上記方法を取りました。
使用可能なオブジェクトが存在しない場合
まずはフォームの中に使用可能な(選択可能な)オブジェクトが存在しない場合の発生イベントは以下の順番で発生します。
| ID | 処理名 | 対象 |
|---|---|---|
| 1 | 開く時 | フォーム |
| 2 | 読込時 | フォーム |
| 3 | サイズ変更時 | フォーム |
| 4 | アクティブ時 | フォーム |
| 5 | フォーカス取得後 | フォーム |
| 6 | レコード移動時 | フォーム |
| 7 | 描画時 | フォームヘッダー |
| 8 | 描画時 | 詳細 |
| 9 | 描画時 | フォームフッター |
| 10 | 描画時 | フォームヘッダー |
| 11 | 描画時 | 詳細 |
| 12 | 描画時 | フォームフッター |
| 13 | 描画時 | フォームヘッダー |
| 14 | 描画時 | フォームヘッダー |
| 15 | 描画時 | 詳細 |
| 16 | 描画時 | 詳細 |
| 17 | 描画時 | フォームフッター |
| 18 | 描画時 | フォームフッター |
| 19 | 読込解除時 | フォーム |
| 20 | フォーカス喪失時 | フォーム |
| 21 | 非アクティブ時 | フォーム |
| 22 | 閉じる時 | フォーム |
この結果から分かる重要なポイントは以下です。
- Form_Open / Load は1回だけ実行される
- Form_Current はレコードソースの有無に関係なく発生する
- 描画時(Paint)イベントは想像以上に複数回呼ばれる
6の「レコード移動時」イベントはレコードソースとしてテーブルを指定していても、指定していなくても同様に発生していました。
今回この検証をして驚いたのが、7~18で発生している「描画時」イベントです。
フォームを開き終わるまでにフォームヘッダー・詳細・フォームフッターでそれぞれ4回描画していることが分かります。
閉じる時に描画を行っている可能性もあったので、念のためクエリに処理した時間を追記して再検証しました。
この検証後、処理を分離するために開き終わって10秒程度触らずに、10秒経ったらxボタンで閉じる操作を実施しました。
結果、「描画時」イベントがフォームを開いている時に4回発生しているということで間違いありませんでした。
もし「描画時」イベントに処理をすることを考える場合、重複した処理が発生しないよう注意が必要です。
使用可能なオブジェクトが存在する場合
次に、フォームの詳細に使用可能なテキストボックスを追加し、開いて閉じる操作を実行してみました。
実行結果は以下の表の通りです。
| ID | 処理名 | 対象 |
|---|---|---|
| 1 | 開く時 | フォーム |
| 2 | 読込時 | フォーム |
| 3 | サイズ変更時 | フォーム |
| 4 | アクティブ時 | フォーム |
| 5 | レコード移動時 | フォーム |
| 6 | フォーカス取得時 | テキストボックス |
| 7 | フォーカス取得後 | テキストボックス |
| 8 | 描画時 | フォームヘッダー |
| 9 | 描画時 | 詳細 |
| 10 | 描画時 | フォームフッター |
| 11 | 描画時 | フォームヘッダー |
| 12 | 描画時 | 詳細 |
| 13 | 描画時 | フォームフッター |
| 14 | 描画時 | フォームヘッダー |
| 15 | 描画時 | フォームヘッダー |
| 16 | 描画時 | 詳細 |
| 17 | 描画時 | 詳細 |
| 18 | 描画時 | フォームフッター |
| 19 | 描画時 | フォームフッター |
| 20 | フォーカス喪失時 | テキストボックス |
| 21 | フォーカス喪失後 | テキストボックス |
| 22 | 読込解除時 | フォーム |
| 23 | 非アクティブ時 | フォーム |
| 24 | 閉じる時 | フォーム |
変わったところはフォームにフォーカスが映らないというところです。
フォーカス取得が可能なオブジェクト(使用可能なテキストボックスやコマンドボタンなど)が存在する場合、フォームにはフォーカスが移動せず、オブジェクトに直接フォーカスが移動することが分かります。
まとめ
Accessのフォームを開いて閉じるまでに発生するイベントの順番を調査し紹介しました。
用途別おすすめイベント例
- 初期化処理 → Form_Load
- 表示制御(初回のみ) → Form_Current(フラグ管理前提)
- サイズ・レイアウト調整 → Form_Resize
- 描画依存の処理 → 原則非推奨(Paintは多重発火するため)
今回の検証で描画時イベントの複数回発生について気になったので、後日検証してみようと思います。
Accessで処理を作成する際、適切なタイミングで処理しないと思ってもいない現象が起こることがあります。
適切なタイミングを見つけるようにしましょう。
困ったら検証してみても良いかもしれません。
効率化が求められる昨今、ノーコードのソフト開発も簡単にできるようになってきていますが、色々作れるに越したことはありません。
色々弄って試してみてください。

コメント