#2 メイン/サブフォームのオープン・クローズ

ここに出てくるイベント
  • Open/開く時
  • Load/読み込み時
  • Resize/サイズ変更時
  • Activate/アクティブ時
  • Current/レコード移動時
  • Unload/読み込み解除時
  • Deactivate /非アクティブ時
  • Close/閉じる時


メイン/サブフォームの準備

「#1 フォームのオープン・クローズ」では、単一のフォームについて、そのイベントの発生状況を調べてみました。しかし、"フォーム"というオブジェクトにはもう1つの形態があります。それは「メイン/サブフォーム」という、フォームの中に、もう1つのフォームを"コントロール"という形で配置したものです。コントロールという扱いにはなっているものの、データベースウィンドウの[フォーム]タブを見れば分かるように、普通のフォームとして一覧に表示されていることから、オブジェクトとしてはあくまでも"フォーム"に間違いありません。それならば、当然、メインフォームのオープン・クローズに伴い、サブフォームにおいても、「#1 フォームのオープン・クローズ」でトレースされたような、各フォームイベントが発生しているはずです。さて、そこで問題となるのが、メインフォームとサブフォーム、それら個々のイベントがどのような順番に絡み合ってイベントが発生しているのかという点です。ここでは、その点について、単一のフォームときの同じ方法を使って、イベントの発生をトレースしてみたいと思います。


メイン/サブフォームのデザイン画面まず、その準備として、メイン/サブフォームを作成します。ここでは、右図のように、フォーム「frm顧客マスタ_sub」をサブフォームとするメインフォーム「frm顧客マスタ」を作成しました。前回使った「frm顧客マスタ」をそのまま「frm顧客マスタ_sub」にリネームしています。メインフォーム側は、単純に「frm顧客マスタ_sub」をサブフォームとして配置しただけのフォームです。なお、レコードソースも持たないため、"レコードセレクタ"と"移動ボタン"プロパティは「いいえ」に設定してあります。


プロパティシートの設定各イベントのプロパティは、メインフォームもサブフォームも、前回と同様、右図のような設定になっています。



フォームイベントのトレース

それでは、このメイン/サブフォームを開いて、そのまますぐに閉じるという操作を行ってみましょう。そのあと、VBE画面に移動してイミディエイトウィンドウを確認してみます。その結果は次のようになりました。ここでは、1〜9までがフォームが開く際のイベント、10以降が閉じる際のイベントです。

発生順序 オブジェクト名 イベント名
1 frm顧客マスタ_sub 開く時
2 frm顧客マスタ_sub 読み込み時
3 frm顧客マスタ_sub サイズ変更時
4 frm顧客マスタ_sub レコード移動時
5 frm顧客マスタ 開く時
6 frm顧客マスタ 読み込み時
7 frm顧客マスタ サイズ変更時
8 frm顧客マスタ アクティブ時
9 frm顧客マスタ レコード移動時
10 frm顧客マスタ 読み込み解除時
11 frm顧客マスタ 非アクティブ時
12 frm顧客マスタ 閉じる時
13 frm顧客マスタ_sub 読み込み解除時
14 frm顧客マスタ_sub 閉じる時


この結果をいくつかのポイントに整理すると、次のようになります。
  1. サブフォームが開かれてからメインフォームが開かれる
  2. メインフォームが閉じられてからサブフォームが閉じられる
  3. メインフォーム、サブフォーム個々のイベント発生順序は同じである
  4. サブフォームでは"アクティブ時"イベントと"非アクティブ時"イベントは発生しない

単純に考えると、まずメインフォームが形成されて、その次に、メインフォーム内の1つのコントロールであるサブフォームが開かれるというイメージがありますが、実はまったく逆の動作をしていることが分かると思います。メイン/サブフォームを表示するだけなら、これらの順序を気にする必要はまったくないわけですが、イベントプロシージャを使ったプログラミングを行う際には、これは非常に注意を要する動作といえるでしょう。メインフォームの"読み込み時"イベントを使ってメインフォームの標題を変更したり、サブフォームの"読み込み時"イベントを使ってサブフォームの何らかのプロパティを設定したりといった、メインフォーム自身およびサブフォーム自身における、イベントによるプロパティ設定なら特に問題はないかもしれません。しかし、メインフォーム・サブフォーム間にまたがるプロパティ設定には何らかの影響が出そうです。特に、サブフォームの"読み込み時"イベントを使って、メインフォームのプロパティを設定するような処理を実行しようとした場合、上記の結果からすると、メインフォームはまだ開かれていないわけですから、そのプロパティ設定を行うということはできないはずです。

一方、dについて考えてみましょう。"アクティブ時"・"非アクティブ時"はフォームだけが持っているイベントです。これは、「frm顧客マスタ_sub」が"フォーム"オブジェクトではあっても、メイン/サブフォームという形態においては、あくまでもメインフォームの中に配置された、テキストボックスなどと同様の1つのコントロールに過ぎないということの表れと考えることができます。それなら、"コントロール"のイベントとして、フォーカス取得を検出するイベントが発生していると考えられます。




そこで、続いて、それらの疑問も含めて、いくつかの検証を行ってみることにしましょう。


メインフォームの読み込み時にサブフォームのプロパティ設定をしてみる

デザイン時の配色上記の結果から判断すると、これは何ら問題ないはずです。メインフォームが読み込まれる時点では、すでにサブフォームは完全に開いた状態になっているからです。一応確認として、次のような"Load/読み込み時"イベントプロシージャをメインフォームのモジュールに記述して試してみましょう。

このコードは、サブフォームの詳細セクションの背景色を白に設定変更するものです。デザイン上、サブフォームの詳細セクションの背景色は灰色になっていますので、うまく動作すれば、メインフォームが画面表示された時点で、サブフォームの背景色は白になっているはずです。なお、サブフォームのコントロールとしての名称は「frm顧客マスタ_sub」になっています。「Me!frm顧客マスタ_sub.Form・・・・・」のコードの部分の"frm顧客マスタ_sub"という記述は、データベースウィンドウ上に表示されているフォーム名ではなく、サブフォームコントロールの「名前」プロパティであることに注意してください。

Private Sub Form_Load()

  Me!frm顧客マスタ_sub.Form.Section(acDetail).BackColor = vbWhite

End Sub

実行後の配色「frm顧客マスタ」を開いてみましょう。

ご覧のように、問題なく、サブフォームの背景色が白になっています。



サブフォームの読み込み時にメインフォームのプロパティ設定をしてみる

さて、今度は逆のパターンです。サブフォームの"Load/読み込み時"イベントプロシージャを使って、メインフォームのプロパティを変更してみます。すでに想定しているように、メインフォームが開く前にそのプロパティを設定しようという、問題の起こりそうな処理です。

今後は、サブフォームの"Load/読み込み時"イベントプロシージャに次のようなコードを記述します。ここで、「Parent」は、直訳すると親という意味で、サブフォームから見たメインフォームのことを指しています。つまりこのコードは、サブフォームの読み込み時にメインフォームの標題(Caption)を変更するコードということになります。

Private Sub Form_Load()

  Parent.Caption = "標題のテスト"

End Sub

それでは、「frm顧客マスタ」を開いてみましょう。

標題が変更されたフォームその結果が右の図です。予想に反して、うまく動作してしまいました。何の問題なく、サブフォームから、まだ開かれていないはずのメインフォームのプロパティを変更することができました。このときのイベント発生順序も特に変わった様子はありません。
このコードを実行することによって、サブフォームの"サイズ変更時"や"レコード移動時"イベントを飛び越して、メインフォームが開かれる際のイベントが発生しているわけでもありません。
その詳しい理由は分かりませんが、イベントは発生していなくても、実際は、サブフォームが開かれた時点で、すでにメインフォームにアクセスすることが可能性であることは確かなようです。

しかしながら、やはり、この時点ではメインフォームの"開く時"イベントが発生していないという事実を考えると、いかなる場合でも100%このような操作がうまくいくかどうかは心配が残ります。「サブフォームが開かれてからメインフォームが開かれる」ということはよく覚えておいた方がよいでしょう



サブフォームの"開く時"イベントをキャンセルしてみる

「#1 フォームのオープン・クローズ」で、"Open/開く時"イベントプロシージャの引数「Cancel」を"True"に設定すると、そのフォームが開かれないということを説明しました。ではもしも、この設定をメイン/サブフォームのサブフォーム側で実行したらどうなるのでしょう。メインフォーム側のオープンもキャンセルされるのでしょうか。次のようなコードをサブフォームのモジュールに記述して、試してみましょう。

Private Sub Form_Open(Cancel As Integer)

  Cancel = True

End Sub

実行後の画面「frm顧客マスタ」を開いてみると、右図のような画面が表示されました。

ご覧のように、本来、サブフォームが表示される部分が真っ白な状態でフォームが表示されています。つまり、サブフォームは確かに開かれていないことが分かります。しかし、メインフォーム側のオープンには何ら影響を与えていません。メインフォームにとっては、その中の1つのコントロールが空欄になっただけということになります。

とはいえ、サブフォーム側の要因でメインフォームを開かないようにするという場面はあまりないでしょう。仮に、そのようなことがあったとしても、メインフォーム側でサブフォームのそのような要因を検出し、メインフォームを開かないようにすればよいだけです。



メインフォームの読み込み時にサブフォームの"ソースオブジェクト"プロパティを設定したらどうなる?

今回使ったメイン/サブフォームでは、サブフォーム(コントロール)の"ソースオブジェクト"プロパティが「frm顧客マスタ_sub」に初めから固定されていました。しかし、メインフォームの"Load/読み込み時"イベントプロシージャで、その設定を動的に変更することもできます。つまり、何らかの条件によって、サブフォームを別のフォームに切り替えることができるのです。

それには、次のようなイベントプロシージャを使います。この例では、○○○○○という部分の条件に応じて、サブフォームを「frm顧客マスタ_sub」か「frm仕入先マスタ_sub」に切り替えるようにしています。

Private Sub Form_Load()

  TrackEvents Me.Name, "読み込み時"

  If ○○○○○ Then
    Me!frm顧客マスタ_sub.SourceObject = "frm顧客マスタ_sub"
  Else
    Me!frm顧客マスタ_sub.SourceObject = "frm仕入先マスタ_sub"
  End If

End Sub


実行前のデザイン画面今回は、If Then〜Elseの分岐は使わずに、「Me!frm顧客マスタ_sub.SourceObject = "frm顧客マスタ_sub"」の行が実行されるようにして、動きを確認してみます。
メインフォームに配置されているサブフォームの"ソースオブジェクト"プロパティの欄をいったん空欄にした上で、「frm顧客マスタ」を開いてみます。


実行後のデザイン画面すると、図のように、これまでと同じように、サブフォームが表示されていることが分かると思います。


このときのイベントの発生状況はどうなっているのでしょうか?。VBEのイミディエイトウィンドウを確認してみましょう。
実行結果のイミディエイトウィンドウ

非常に興味深い結果になったと思いませんか?。プロパティ設定やコードの処理順にしたがって、思ったとおりにイベントが発生していることが分かります。どういうことかというと、メインフォームにはサブフォームがコントロールとして配置されているものの、肝心のソースオブジェクトが設定されていないため、サブフォームを開きようがないのです。そのため、サブフォームのオープンに関わるイベントは発生せず、メインフォームのオープン関連イベントが最初に発生します。そして、メインフォームの"Load/読み込み時"イベントプロシージャが実行され、ソースオブジェクトが指定されると、直ちにサブフォームのオープン処理が実行されているのです。そして、その間、メインフォームの"サイズ変更時"イベントなどは後回しにされていることが分かります。



サブフォームの"コントロール"としてのイベント発生は?

前にも説明した通り、サブフォームというものは、"フォーム"オブジェクトであると同時に、メインフォームにとっては、テキストボックスやコンボボックスなどと同類の1つのコントロールとして見ることができます。それは、そのサブフォームコントロールが選択されている状態でのプロパティシートを見てみれば分かります。コントロールという立場でサブフォームが選択されているときには、"フォーカス取得時"と"フォーカス喪失時"の2つのイベントを持っています。

ここに、フォームと同様のTrackEvents()プロシージャ呼び出しを設定してみます。
イベントのプロパティ設定


この状態で、フォームを開いて、イベントの発生順序を確認してみましょう。
実行結果のイミディエイトウィンドウ

ご欄のように、メイン/サブフォームのオープンが完了した後、コントロールとしてのサブフォームにフォーカスが移動していることが確認できます。
ただし、メインフォームにおいて、サブフォーム(コントロール)のタブオーダーが先頭になっていない場合には、このような結果にはなりません。メインフォームが開いた直後は、タブオーダーが先頭となっているコントロールにフォーカスが移動するためです。


| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved