#5 フォームとテキストボックスの更新系イベントの違い

ここに出てくるイベント
  • BeforeUpdate/更新前処理
  • AfterUpdate/更新後処理


フォームやコントロールでは、別のオブジェクトであっても、似たような名前あるいはまったく同じ名前のイベントがいくつも見受けられます。例えば、"更新前処理"イベント"更新後処理"イベントはフォームにもありますし、テキストボックスコントロールにも存在しています。

フォームのイベント テキストボックスのイベント

また、コンボボックスやリストボックスコントロールにも存在しています。テキストボックスやコンボボックスなど、コントロールから発生されるイベントは、そのコントロールに何らかの更新操作が与えられたときに発生するのであろうと想像できますが、フォームの更新系イベントの発生との兼ね合いはどのようになっているのでしょうか?。

ここでは、上図のように、フォームの"更新前処理"イベント・"更新後処理"イベント、およびテキストボックスである「氏名」と「役職」の2つにイベントトレース用のプロシージャ呼び出しを記述し、その流れを追ってみたいと思います。



テキストボックスのデータを編集してみる

まず、テキストボックス単体でのイベント発生状況を確認してみましょう。テキストボックス「氏名」・「役職」に対して、次のような操作を実行してみます。
  1. テキストボックス「氏名」の内容を書き換える
  2. TABキーによってフォーカスを「役職」まで移動する
  3. テキストボックス「役職」の内容を書き換える
  4. Enterキーを押して、「役職」の内容を確定する

その結果は次のようになりました。


発生順序 オブジェクト名 イベント名
1 氏名テキストボックス 更新前処理
2 氏名テキストボックス 更新後処理
3 役職テキストボックス 更新前処理
4 役職テキストボックス 更新後処理


これを上記の操作手順と照らし合わせてみましょう。

まず、『1.テキストボックス「氏名」の内容を書き換える』という操作だけでは、何のイベントも発生しません(実際には"変更時"イベントが発生していますが、これについては別途取り上げます)。データ内容は変更されているものの、データベース上においては、まだ仮の入力状態にあるといえるでしょう。

続いて、『2.TABキーによってフォーカスを「役職」まで移動する』という操作ですが、この時点で、上表の"更新前処理"イベント・"更新後処理"イベントが同時に発生します。厳密には、「役職」にフォーカスが移動したときではなく、「氏名」のテキストボックスからフォーカスが喪失したときに発生します。つまり、フォーカスが喪失したときにはじめて、イベントとしてはそのテキストボックスが更新されたと判断されていることになります。

続いての『3.テキストボックス「役職」の内容を書き換える』と『4.Enterキーを押して、「役職」の内容を確定する』についても、同様の結果となります。内容を書き換えただけで、またフォーカスが「役職」欄にあるうちは、何らイベントは発生しません。先ほどはTABキーによってフォーカスを移動しましたが、Enterキーによってもフォーカスが次のコントロールに移動しますので、その時点で"更新前処理"イベント・"更新後処理"イベントが同時に発生します。



フォームの更新系イベントはいつ発生するのか?

上記のテストを行う際には、フォームの"更新前処理"・"更新後処理"イベントのプロパティを空欄にしてあったわけではありません。それぞれ「=TrackEvents([Name],"更新前処理")」や「=TrackEvents([Name],"更新後処理")」というトレース用のプロシージャを呼び出すようにしてありました。しかし、VBEのイミディエイトウィンドウを確認しても、それらのイベントは確かに発生していません。それでは、それらフォームの更新系イベントはいつ発生するのでしょうか?。

結論からいうと、そのレコードが保存されたときに発生します。試しに、上記4つの操作を行ったあとで、単票フォームのレコードセレクタをクリックしてみましょう。
操作例


その結果をイミディエイトウィンドウで確認してみます。ご覧のように、最後(レコードセレクタクリック時)に「フォーム」の"更新前処理"イベントと"更新後処理"イベントが発生していることが分かります。
実行結果のイミディエイトウィンドウ

このフォームのイベントが発生するタイミングを「レコードが保存されたとき」と言いましたが、レコードが保存されるタイミングはレコードセレクタをクリックする以外にもあります。例えば、
  • TABキーでコントロールを次々の移動していき、次のレコードにカレントレコードが移ったとき(Shift+TABキーで前のレコードに移動したときも同様)

  • レコード移動ボタンでレコードを移動させたとき

  • フォームを閉じたとき
などにもレコードが保存されますので、同様に、フォームのイベントが発生します。



フォームとテキストボックスの更新系イベントの使い分け

テキストボックス単体での更新系イベントの発生状況、およびフォームも含めた更新系イベントの発生状況について調べてきましたが、イベントプロシージャを活用する際に、これらはどのような考え方で使い分けを行えばよいのでしょうか?。

それを考える上での、要点を整理しておきましょう。
  • テキストボックス単体でデータ編集を行うと、テキストボックスの更新系イベントが発生する
  • レコードを保存すると、フォームの更新系イベントが発生する

つまり、
  • 「氏名」なら「氏名」、あるいは「役職」なら「役職」という個々のデータが変更されたかをチェックし、それにもとづいて何らかのアクションを起こしたいなら、テキストボックスの更新系イベントプロシージャを使う

  • 「レコードを保存すると」とありますが、もちろん、どのテキストボックスも更新されていない状態でレコードを保存してもフォームの更新系イベントは発生しません。つまり、フォームの更新系イベントは、「どのテキストボックス(あるいはコンボボックスやリストボックス)かは分からないが、レコードのいずれかのフィールドに変更が加えられたとき」に発生するわけです。このことから、特定のコントロールに関わりなく、レコード全体の更新をチェックし、それにもとづいてアクションを起こしたいなら、フォームの更新系イベントプロシージャを使う

といった考え方で両者のイベントを使い分ければよいことになります。


それでは、その使い分け例を次に示します。

次のフォームのモジュールの例では、まず、「氏名」が更新されたら、姓と名がスペースで区切られているかをチェックします。そんなに厳密なチェックではなく、単に氏名のデータの中にスペースが1つ以上存在しているかチェックするだけです。そして、レコードが保存(移動)されたときに"レコードが編集されたかどうかチェック"し、もし編集が行われていたら、フォームモジュール内でグローバルな、レコード編集が行われたかどうかのフラグ変数をTrueに設定します。そして、フォームが閉じる際に、レコード編集が行われていたらその旨のメッセージを表示します。このとき、"レコードが編集されたかどうかチェック"とありますが、特にそのチェック用のコードを記述するわけではなく、レコードが編集されていない場合にはフォームの更新系イベントは発生しませんので、「イベントが発生した=レコードが編集された」と判断することにします。

Option Compare Database
Option Explicit

Private plnEditFlg As Boolean '編集フラグ

Private Sub Form_AfterUpdate()
'フォームの更新後処理

  '編集フラグをONにする
  plnEditFlg = True

End Sub

Private Sub Form_Close()
'フォームが閉じる時

  If plnEditFlg Then
    '編集フラグをONのとき
    Beep
    MsgBox "レコード編集されました!"
  End If

End Sub
実行結果のメッセージ


Private Sub 氏名_BeforeUpdate(Cancel As Integer)
'氏名テキストボックスの更新前処理

  If InStr(Me!氏名, " ") = 0 Then
    '氏名の中にスペースがないとき
    Beep
    MsgBox "姓名はスペースで区切ってください!"
    Cancel = True
  End If

End Sub
実行結果のメッセージ



更新前処理イベントと更新後処理イベントの使い分け

上記のコードでは、フォームの2つの更新系イベントとテキストボックスの2つの更新系イベント、合計4つのすべてのイベントを使っているわけではありません。「氏名」のチェックでは"更新前処理"イベントを、一方、レコード編集のチェックでは"更新後処理"イベントだけを使っています。これは、"更新前処理"イベントと"更新後処理"イベントの使い分けのポイントともなることですので、ここで簡単に説明しておきましょう。

その違いを知るには、各イベントプロシージャの引数を確認するのが一番よいでしょう。


イベント名 宣言
フォームの更新前処理 Private Sub Form_BeforeUpdate(Cancel As Integer)
フォームの更新後処理 Private Sub Form_AfterUpdate()
テキストボックスの更新前処理 Private Sub 氏名_BeforeUpdate(Cancel As Integer)
テキストボックスの更新後処理 Private Sub 氏名_AfterUpdate()


ご覧のように、大きな違いは「Cancel」という名前の引数の有無にあります。"更新前処理"イベントでは、イベントプロシージャの中でこの値を「True」に設定することによって、そのイベントの発生元となった操作を取り消すことができるのです。

上記のコードでは、「氏名」のチェックに"更新前処理"イベントプロシージャを使い、もし氏名データの中にスペースがなければCancel変数をTrueにしています。つまり、スペースを含まない氏名を入力したときには、その入力操作をキャンセルするようになっているのです。イベントプロシージャによって入力がキャンセルされると、もう一度その欄にデータを入力させるため、「氏名」欄からフォーカスが移動しません。入力した氏名データ全体が反転表示の状態になって、他のコントロールに移動できないようになります。

一方、レコード編集のチェックでは、レコードが編集されていようがいまいが、その編集操作を取り消すという処理は必要ありません。あくまでも編集されたかどうかをチェックするだけです。したがって、「Cancel」引数を利用する必要はありませんので、"更新後処理"イベントの方を使っているわけです。ただし、このようなチェックなら、たとえ"更新前処理"イベントでやってしまっても特に違いはでないでしょう。

| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved