#2 | メイン/サブフォームのオープン・クローズ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
「#1 フォームのオープン・クローズ」では、単一のフォームについて、そのイベントの発生状況を調べてみました。しかし、"フォーム"というオブジェクトにはもう1つの形態があります。それは「メイン/サブフォーム」という、フォームの中に、もう1つのフォームを"コントロール"という形で配置したものです。コントロールという扱いにはなっているものの、データベースウィンドウの[フォーム]タブを見れば分かるように、普通のフォームとして一覧に表示されていることから、オブジェクトとしてはあくまでも"フォーム"に間違いありません。それならば、当然、メインフォームのオープン・クローズに伴い、サブフォームにおいても、「#1 フォームのオープン・クローズ」でトレースされたような、各フォームイベントが発生しているはずです。さて、そこで問題となるのが、メインフォームとサブフォーム、それら個々のイベントがどのような順番に絡み合ってイベントが発生しているのかという点です。ここでは、その点について、単一のフォームときの同じ方法を使って、イベントの発生をトレースしてみたいと思います。 まず、その準備として、メイン/サブフォームを作成します。ここでは、右図のように、フォーム「frm顧客マスタ_sub」をサブフォームとするメインフォーム「frm顧客マスタ」を作成しました。前回使った「frm顧客マスタ」をそのまま「frm顧客マスタ_sub」にリネームしています。メインフォーム側は、単純に「frm顧客マスタ_sub」をサブフォームとして配置しただけのフォームです。なお、レコードソースも持たないため、"レコードセレクタ"と"移動ボタン"プロパティは「いいえ」に設定してあります。 各イベントのプロパティは、メインフォームもサブフォームも、前回と同様、右図のような設定になっています。
それでは、このメイン/サブフォームを開いて、そのまますぐに閉じるという操作を行ってみましょう。そのあと、VBE画面に移動してイミディエイトウィンドウを確認してみます。その結果は次のようになりました。ここでは、1〜9までがフォームが開く際のイベント、10以降が閉じる際のイベントです。
この結果をいくつかのポイントに整理すると、次のようになります。
単純に考えると、まずメインフォームが形成されて、その次に、メインフォーム内の1つのコントロールであるサブフォームが開かれるというイメージがありますが、実はまったく逆の動作をしていることが分かると思います。メイン/サブフォームを表示するだけなら、これらの順序を気にする必要はまったくないわけですが、イベントプロシージャを使ったプログラミングを行う際には、これは非常に注意を要する動作といえるでしょう。メインフォームの"読み込み時"イベントを使ってメインフォームの標題を変更したり、サブフォームの"読み込み時"イベントを使ってサブフォームの何らかのプロパティを設定したりといった、メインフォーム自身およびサブフォーム自身における、イベントによるプロパティ設定なら特に問題はないかもしれません。しかし、メインフォーム・サブフォーム間にまたがるプロパティ設定には何らかの影響が出そうです。特に、サブフォームの"読み込み時"イベントを使って、メインフォームのプロパティを設定するような処理を実行しようとした場合、上記の結果からすると、メインフォームはまだ開かれていないわけですから、そのプロパティ設定を行うということはできないはずです。 一方、dについて考えてみましょう。"アクティブ時"・"非アクティブ時"はフォームだけが持っているイベントです。これは、「frm顧客マスタ_sub」が"フォーム"オブジェクトではあっても、メイン/サブフォームという形態においては、あくまでもメインフォームの中に配置された、テキストボックスなどと同様の1つのコントロールに過ぎないということの表れと考えることができます。それなら、"コントロール"のイベントとして、フォーカス取得を検出するイベントが発生していると考えられます。 そこで、続いて、それらの疑問も含めて、いくつかの検証を行ってみることにしましょう。
上記の結果から判断すると、これは何ら問題ないはずです。メインフォームが読み込まれる時点では、すでにサブフォームは完全に開いた状態になっているからです。一応確認として、次のような"Load/読み込み時"イベントプロシージャをメインフォームのモジュールに記述して試してみましょう。 このコードは、サブフォームの詳細セクションの背景色を白に設定変更するものです。デザイン上、サブフォームの詳細セクションの背景色は灰色になっていますので、うまく動作すれば、メインフォームが画面表示された時点で、サブフォームの背景色は白になっているはずです。なお、サブフォームのコントロールとしての名称は「frm顧客マスタ_sub」になっています。「Me!frm顧客マスタ_sub.Form・・・・・」のコードの部分の"frm顧客マスタ_sub"という記述は、データベースウィンドウ上に表示されているフォーム名ではなく、サブフォームコントロールの「名前」プロパティであることに注意してください。
「frm顧客マスタ」を開いてみましょう。 ご覧のように、問題なく、サブフォームの背景色が白になっています。
さて、今度は逆のパターンです。サブフォームの"Load/読み込み時"イベントプロシージャを使って、メインフォームのプロパティを変更してみます。すでに想定しているように、メインフォームが開く前にそのプロパティを設定しようという、問題の起こりそうな処理です。 今後は、サブフォームの"Load/読み込み時"イベントプロシージャに次のようなコードを記述します。ここで、「Parent」は、直訳すると親という意味で、サブフォームから見たメインフォームのことを指しています。つまりこのコードは、サブフォームの読み込み時にメインフォームの標題(Caption)を変更するコードということになります。
それでは、「frm顧客マスタ」を開いてみましょう。 その結果が右の図です。予想に反して、うまく動作してしまいました。何の問題なく、サブフォームから、まだ開かれていないはずのメインフォームのプロパティを変更することができました。このときのイベント発生順序も特に変わった様子はありません。 このコードを実行することによって、サブフォームの"サイズ変更時"や"レコード移動時"イベントを飛び越して、メインフォームが開かれる際のイベントが発生しているわけでもありません。 その詳しい理由は分かりませんが、イベントは発生していなくても、実際は、サブフォームが開かれた時点で、すでにメインフォームにアクセスすることが可能性であることは確かなようです。 しかしながら、やはり、この時点ではメインフォームの"開く時"イベントが発生していないという事実を考えると、いかなる場合でも100%このような操作がうまくいくかどうかは心配が残ります。「サブフォームが開かれてからメインフォームが開かれる」ということはよく覚えておいた方がよいでしょう。
「#1 フォームのオープン・クローズ」で、"Open/開く時"イベントプロシージャの引数「Cancel」を"True"に設定すると、そのフォームが開かれないということを説明しました。ではもしも、この設定をメイン/サブフォームのサブフォーム側で実行したらどうなるのでしょう。メインフォーム側のオープンもキャンセルされるのでしょうか。次のようなコードをサブフォームのモジュールに記述して、試してみましょう。
「frm顧客マスタ」を開いてみると、右図のような画面が表示されました。 ご覧のように、本来、サブフォームが表示される部分が真っ白な状態でフォームが表示されています。つまり、サブフォームは確かに開かれていないことが分かります。しかし、メインフォーム側のオープンには何ら影響を与えていません。メインフォームにとっては、その中の1つのコントロールが空欄になっただけということになります。 とはいえ、サブフォーム側の要因でメインフォームを開かないようにするという場面はあまりないでしょう。仮に、そのようなことがあったとしても、メインフォーム側でサブフォームのそのような要因を検出し、メインフォームを開かないようにすればよいだけです。
今回使ったメイン/サブフォームでは、サブフォーム(コントロール)の"ソースオブジェクト"プロパティが「frm顧客マスタ_sub」に初めから固定されていました。しかし、メインフォームの"Load/読み込み時"イベントプロシージャで、その設定を動的に変更することもできます。つまり、何らかの条件によって、サブフォームを別のフォームに切り替えることができるのです。 それには、次のようなイベントプロシージャを使います。この例では、○○○○○という部分の条件に応じて、サブフォームを「frm顧客マスタ_sub」か「frm仕入先マスタ_sub」に切り替えるようにしています。
今回は、If Then〜Elseの分岐は使わずに、「Me!frm顧客マスタ_sub.SourceObject = "frm顧客マスタ_sub"」の行が実行されるようにして、動きを確認してみます。 メインフォームに配置されているサブフォームの"ソースオブジェクト"プロパティの欄をいったん空欄にした上で、「frm顧客マスタ」を開いてみます。 すると、図のように、これまでと同じように、サブフォームが表示されていることが分かると思います。 このときのイベントの発生状況はどうなっているのでしょうか?。VBEのイミディエイトウィンドウを確認してみましょう。 非常に興味深い結果になったと思いませんか?。プロパティ設定やコードの処理順にしたがって、思ったとおりにイベントが発生していることが分かります。どういうことかというと、メインフォームにはサブフォームがコントロールとして配置されているものの、肝心のソースオブジェクトが設定されていないため、サブフォームを開きようがないのです。そのため、サブフォームのオープンに関わるイベントは発生せず、メインフォームのオープン関連イベントが最初に発生します。そして、メインフォームの"Load/読み込み時"イベントプロシージャが実行され、ソースオブジェクトが指定されると、直ちにサブフォームのオープン処理が実行されているのです。そして、その間、メインフォームの"サイズ変更時"イベントなどは後回しにされていることが分かります。
前にも説明した通り、サブフォームというものは、"フォーム"オブジェクトであると同時に、メインフォームにとっては、テキストボックスやコンボボックスなどと同類の1つのコントロールとして見ることができます。それは、そのサブフォームコントロールが選択されている状態でのプロパティシートを見てみれば分かります。コントロールという立場でサブフォームが選択されているときには、"フォーカス取得時"と"フォーカス喪失時"の2つのイベントを持っています。 ここに、フォームと同様のTrackEvents()プロシージャ呼び出しを設定してみます。 この状態で、フォームを開いて、イベントの発生順序を確認してみましょう。 ご欄のように、メイン/サブフォームのオープンが完了した後、コントロールとしてのサブフォームにフォーカスが移動していることが確認できます。 ただし、メインフォームにおいて、サブフォーム(コントロール)のタブオーダーが先頭になっていない場合には、このような結果にはなりません。メインフォームが開いた直後は、タブオーダーが先頭となっているコントロールにフォーカスが移動するためです。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Copyright © T'sWare All rights reserved |