#AccessVBAで他フォームの処理結果を使う
MS Accessを使って事務処理的な業務を回してるようなシーンでは
社員マスタを登録する時に所属部門を検索して入力したいだとか、
商品マスタを登録する時に販売組織を検索して入力したいだとか、
「他のフォーム開いて結果を受け取りたい場面」というのはよくあると思う。
こういう時にどうするべきかググっても某知恵袋とかが出てきて
回答者によって方針が全然違ったりする。ので、メモに残す。
この中では3番目のやり方がましだと思うが、4番目のやり方もあるかもしれない。
##方法1:子フォームから親フォームを直接操作する
ネット上でよく見られるやり方なのかは知らない。
メンテを頼まれたファイルで濫用されている方法なので、きっとそうなのだろう。
Form_Main
Private Sub CommandOpenSubF_Click()
'サブフォームを呼び出して結果を待つ
Call DoCmd.OpenForm(FormName:="SubFoo",WindowMode:=acDialog)
If Len(Me.FooId.Value) > 0 Then
'選択したFooIdの値を必要とする処理
End If
End Sub
Form_SubFoo
'選択したレコードのIDをMainフォームに直接書き込んでSubFフォームを閉じる
Private Sub CommandChoice_Click()
Forms!Form_Main.FooId.Value = Me.FooId.Value
DoCmd.Close
End Sub
- 方法1のメリット
- 多分これが一番早いと思います
- 共用とか考えないなら最も簡単に目的を実現出来る
- 方法1のデメリット
- サブフォームからメインフォームを操作するため、結合がかなり強固
- サブフォームからメインフォームを操作するため、動作が分かりにくい
- やりたい事によってはメインフォームに受取り専用の項目が必要になる
- 同じようなサブフォームが呼び出し元のフォームに対してコピペで生産される
- 同じようなサブフォームが呼び出し元のフォームに対してコピペで生産される
大事なことなので二回書きましたっ!
##方法2:標準モジュールのメンバ変数でやりとりする
Mod_Foo
Public FooId As String
Form_Main
Private Sub CommandOpenSubF_Click()
'サブフォームを呼び出して結果を待つ
Call DoCmd.OpenForm(FormName:="SubFoo",WindowMode:=acDialog)
If Len(Mod_Foo.FooId) > 0 Then
'選択したFooIdの値を必要とする処理
End If
End Sub
Form_SubFoo
'選択したレコードのIDをMod_Fooに書き込んでSubFフォームを閉じる
Private Sub CommandChoice_Click()
Mod_Foo.FooId = Me.FooId.Value
DoCmd.Close
End Sub
- 方法2のメリット
- サブフォームからはメインフォームの存在を気にしなくてよいので結合は弱い
- サブフォームの起動も標準モジュールに押しこめば共通関数的に使える
- 方法2のデメリット
- グローバルスコープに変数を置く事によるデメリットを全部受ける
##方法3:イベントを使う
Form_Main
'SubFooフォームのイベント監視のための宣言
Private WithEvents m__SubFoo As Form_SubFoo
Private Sub CommandOpenSubF_Click()
'サブフォームを呼び出すだけ
Set m__SubFoo = new Form_SubFoo
m__SubFoo.Visible =True
End Sub
Private Sub m__SubFoo_OnSelected(Byval aFooId As String)
Set m__SubFoo = Nothing '用済みなのでさっさと参照を破棄する
'選択したFooIdの値を必要とする処理
End Sub
Form_SubFoo
'IDを選択したイベント
Public Event OnSelected(ByVal aFooId As String)
'選択したレコードのIDでOnSelectedイベントを起こす
Private Sub CommandChoice_Click()
RaiseEvent OnSelected(Me.FooId.Value)
End Sub
- 方法3のメリット
- サブフォームからはメインフォームの存在を気にしなくてよいので結合は弱い
- グローバルスコープも使わないで済む
- サブフォームの型を明示して使うので、Publicなプロシージャがあれば呼び出せる
- サブフォーム部品(フォーム内に別フォームを埋め込む部品)でも応用できる。
- 方法3のデメリット
- 他の方法に比べるとイベントを書くのは結構面倒くさい
- サブフォームを「作業ウィンドウ固定」にしていないとモードレスになる
- イベントの名前を変えてもエラーにならず、静かに失敗する
- イベントのシグネチャを変えてもエラーにならず、静かに失敗する
2015/12/31 一部修正
- 方法1と2のコードにCallキーワードが抜けていたのを追記