5
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AccessVBAで他フォームの処理結果を使う

Last updated at Posted at 2015-06-17

#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. 共用とか考えないなら最も簡単に目的を実現出来る
  • 方法1のデメリット
  1. サブフォームからメインフォームを操作するため、結合がかなり強固
  2. サブフォームからメインフォームを操作するため、動作が分かりにくい
  3. やりたい事によってはメインフォームに受取り専用の項目が必要になる
  4. 同じようなサブフォームが呼び出し元のフォームに対してコピペで生産される
  5. 同じようなサブフォームが呼び出し元のフォームに対してコピペで生産される
    大事なことなので二回書きましたっ!

##方法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のメリット
  1. サブフォームからはメインフォームの存在を気にしなくてよいので結合は弱い
  2. サブフォームの起動も標準モジュールに押しこめば共通関数的に使える
  • 方法2のデメリット
  1. グローバルスコープに変数を置く事によるデメリットを全部受ける

##方法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のメリット
  1. サブフォームからはメインフォームの存在を気にしなくてよいので結合は弱い
  2. グローバルスコープも使わないで済む
  3. サブフォームの型を明示して使うので、Publicなプロシージャがあれば呼び出せる
  4. サブフォーム部品(フォーム内に別フォームを埋め込む部品)でも応用できる。
  • 方法3のデメリット
  1. 他の方法に比べるとイベントを書くのは結構面倒くさい
  2. サブフォームを「作業ウィンドウ固定」にしていないとモードレスになる
  3. イベントの名前を変えてもエラーにならず、静かに失敗する
  4. イベントのシグネチャを変えてもエラーにならず、静かに失敗する

2015/12/31 一部修正

  • 方法1と2のコードにCallキーワードが抜けていたのを追記
5
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?