[[20120522093647]] 『フォーム間の値の受け渡し』(コツ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『フォーム間の値の受け渡し』(コツ)

フォームの値の受け渡しについて教えてください。

フォーム@のテキストボックスに名前を入力する為に、
フォームAで検索して、リストボックスの中から該当する箇所をクリックしたとき、
フォーム@のテキストボックスに値が入力されるようにしたいです。

ただ、フォームAでの検索は、フォーム@からだけでなく、
フォームBやフォームCの値を入力する際にも利用できるようにしたいのですが、
どのモジュールに記述すればよいか、また、宣言はなんなのか分かりません。

よろしくお願いします。
バージョンは2007です。
コツ


[[20120521100804]] 『別フォームの値を表示する』(nin)

 HNは異なっているけど、フォームAを共通的に複数のフォームで使用する場合の対応方法だね。
 同じ人か別の人かわからないけど、別の人だったら、上のトピが参考にならないかな?

 (「宣言は何なのかわかりません」という表現も、上のトピと同じなので、同じ人かな?)

 (ぶらっと)

昨日はありがとうございました。
今回は、参考になるんでしょうけど、分かりません。
今回もよろしくお願いします。

前回の質問は、カレンダーでしたが

With frmカレンダー
.Show
cbo日付.Value = .Calendar1.Value
End With
できました。

今回の場合は、.Calendar1.Valueの部分が、
リストボックスの中をチェック時に実行する場合、

Private Sub Calendar1_Click()
Unload Me
End sub
にどう修正すればよいかわかりません。

よろしくお願いします。


 >リストボックスの中をチェック時に実行する場合、

 つまり、フォームAにリストボックスがあって、そのリストボックスから選んだときに
 選ばれた値を、呼び出したフォームのテキストボックスにセットするということじゃないの?

 それとも、「リストボックスの中をチェック時」という表現は、フォームA側で、リストボックスから選んだときに
 なんらかのチェックロジックが働くということ?
 そのあたりが、わからないので・・・・

 もし、リストボックスで選んだ瞬間に、その値を呼び出したフォームのテキストボックスにセットするなら
 前回と同じコードでいいんだよ。

 フォーム@ 側

 With フォームA 
    .Show 
    TestBox1.Value = .ListBox1.Value 'TextBox1 や ListBox1 は 実際のコントロール名に。
 End With 

 フォームA 側

 Private Sub ListBox1_Click()   'ListBox1 は実際の名前に
   Unload Me 
 End sub 

 (ぶらっと)


そうなんですね。難しく考えてました。

このフォームAを.詳しく言うと、

Private Sub ListBox1_Click()
ListIdx = ListBox1.ListIndex
Namae = ListBox1.List(ListIdx)
l = Kensaku(ByVal Namae)
フォーム@.TextBox1=Worksheet("名前").Cells(l, 1).Value
Unload Me
End Sub

とリスト内の該当する名前をチェックした際には、
その名前をkensakuで検索し、一致した名前の通し番号を
フォーム@に入力したいのですが、
ListBox1.Value の部分をどう修正すればよいですか?

ご負担おかけしますが、よろしくお願いします。
コツ


 まず、前回、そちらでも言っていたけど、このフォームA内で、
 フォーム@.TextBox1=Worksheet("名前").Cells(l, 1).Value 
 これは具合が悪いよね。フォーム@以外からもとんでくるわけだから。

 いろいろ方法はあるけど、フォームAにテキストボックスを1つ追加。
これはプロパティのVisible をFalseにして非表示にしておこう。
仮にその名前がTextBoxZ だとして、

フォームA側を

 Private Sub ListBox1_Click()
    Namae = ListBox1.Value
    TextBoxZ.Value = Kensaku(ByVal Namae)
    Unload Me
 End Sub

 にしておいて

 フォーム@側を

 With フォームA 
    .Show 
    TestBox1.Value = Worksheet("名前").Cells(.TextBoxZ.Value, 1).Value 
 End With 

 これでどうだろう。

 なお、今から外出。戻りは夜になるので、それまで対応できない。あしからず。

 (ぶらっと)


(ぶらっと)さん
いつもありがとうございます。

思った通りになりました。
仮のテキストボックスなんて絶対思いつきませんでした。

ありがとうございました。
コツ


 ちょっと気になったので・・・。
 コツさんとninさんが同じ方だとすると、私も
[[20120517111530]] 
 でインターフェースに関して、投稿をさせていただきました。
 残念ながら、返信はいただけませんでしたが・・・。

 気になったのは、ぶらっとさんの提示されたコードです。

 ロジック的には、私のコードとおおよそ同じなんですが・・・。
 違いは、対象オブジェクトからの戻り方・・・、

 私
     Me.Hide

 ぶらっとさん
    
        unload me

 ぱっと見、これで呼び出し側で正しく出力データが得られることも驚きでした。
 でも、意味合いから、ここでオブジェクトの削除でよいのか?
 という疑問はのこりました。

     With UserForm2
       .Show
       TextBox1.Value = .Calendar1.Value
     End With

 >With UserForm2
 これが効いていて、UserForm2を参照中だからかなあ と想像していました。
 ただ、呼び出し側でのコードが限定されてしまうかなあという懸念はあります。

 ここからは、Excel2002での現象なので、上位バージョンでは違う なら、
 教えていただきたいのですが・・・。

 上記のコードを

    Dim frm As Userform2
    Set frm = UserForm2
    With frm
       .Show
       TextBox1.Value = .Calendar1.Value
    End With

 では、正しく Calendarオブジェクトのプロパティを取得できていますが、

 変数frmをObject型やVariant型に変更すると

 TextBox1.Value = .Calendar1.Value

 でオートメーションエラーが発生します。

 ちょっと??なので、以下の処理を入れてイベント発生順序を確認。

 UserForm2のTerminateに

 Private Sub UserForm_Terminate()
    Debug.Print "term"
 End Sub

 呼び出し側で

     With UserForm2
       .Show
       Debug.Print "check1"
       TextBox1.Value = .Calendar1.Value
     End With
     Debug.Print "check2"

 結果は、

 term
 check1
 check2

 でどうやら Unload meの時点でTerminateイベントが発生しているように見えます。

 クラスモジュールのTerminateは、全ての参照が消去で実行されたはずですよね?
 ここで動作のメカニズムがわからなくなりました。

 さらにUserForm2に

 テストとして、適当なメソッドを付加してみます。

 UserForm2

 Sub test()
    MsgBox "UserForm2"
 End Sub

 

 呼び出し側で

     With UserForm2
       .Show
       .test
       TextBox1.Value = .Calendar1.Value
     End With

 今度は、.testで オートメーメーションエラーになりました。

 以上がExcel2002での現象ですが、上位バージョンでも精査してみてください。

 この不可解な現象が上位バージョンでも発生するなら、
 やはり、ここは、Me.Hide を使う方が無難かなあ と思いますが、
 いかがですか?
 このスレッドの御質問もテキストボックスを介入させるのではなく、
 普通に変数を使ったプロパティでいけると思いますしね!!

 ichinose


 To ichinoseさん

 いつも、ichinoseさんのレスで勉強させていただいています。
 コメント頂き、光栄かつ深謝です。

 さて、ご指摘の件、もちろん、今回の対応で、一番簡便な方法はパブリック変数による受け渡しですが
 できる限り、パブリック変数を介在させず、呼び出しフォームと共通フォームの当事者間だけのスコープに
 しておきたく、このような構成にしたわけですが、後述するように【実はおっかなびっくり】なコードということは
 認識しています。ただ、一般的な使い方では、おそらく、99%ぐらいは大丈夫かなと。

 まず、Unload なのか Hide なのか。もちろん、Hide にしておけば、何の心配も無く、直接、共通フォームの
 プロパティは参照可能。ただ、スレ主さんから、「表示を消した後は参照できない」とのコメントがあったので
 現在のコードが Unload なんだろうなと、まずそう理解。Hide の場合はメモリーに残っているので、次回
 Show しても、Initialize は実行されないことから、おそらく、(コード提示は無いものの)要件的には Unload だろうと
 これは、スレ主さんに未確認のまま、思い込みもありましたけど。

 で、その Unload を前提にした場合、私が提示したコードで、「通常のプロパティ」は取得可能、これは、仕様として
 そうだということではなく、私の経験上、可能だということです。

 アップいただいたテストコードについては、今から2003で、また夜には2010でテストを行った上で結果報告をしたいと
 そう思っていますが、本件、上で【実はおっかなびっくり】と書きましたように、気になるところは多々あって
 以前、2003で、以下のようなテストをしたことがあります。

 UserForm1 と UseerForm2 を用意。いずれも TextBox1 を配置。

 UserForm1 側

 Private Sub UserForm_Initialize()
    Me.Tag = "ABC"
    TextBox1.Value = "XYZ"
 End Sub

 Private Sub UserForm_Activate()
    Me.Hide
 End Sub

 UserForm2 側

 Private Sub UserForm_Initialize()
    Me.Tag = "ABC"
    TextBox1.Value = "XYZ"
 End Sub

 Private Sub UserForm_Activate()
    Unload Me
 End Sub

 要は、Hide するか Unload するかだけの違い。

 で、標準モジュールに

 Sub Test1()
    With UserForm1
        .Show
        MsgBox "TextBox:" & .TextBox1.Value
        MsgBox "Tag:" & .Tag
    End With
 End Sub

 Sub Test2()
    With UserForm2
        .Show
        MsgBox "TextBox:" & .TextBox1.Value
        MsgBox "Tag:" & .Tag
    End With
 End Sub

 結果は、Test1 は、もちろん 何の問題も無く表示。ところが Test2 のほうは .Tag を表示させようとして
 オートメーションエラー。

 本件については、いくつかの掲示板で過去にディスカッションされているのを目にしたことがありますが

 ・フォーム側で Unload しても、呼び出し側で With で その参照を行っている。この参照を End With で
   終了させるまでは、実際にはメモリーに存在するオブジェクトは消滅しておらず、だから参照可能。

 こういう意見と

 ・オブジェクトは消滅している。ただし、呼び出し側で把握しているオブジェクト参照、つまりメモリー上の
 オブジェクト情報のアドレスは、「他のメモリー要求がない限りそのままのイメージで残っている」
 なので、参照可能。

 こういう意見があって、私の場合、希望的観測で、「前者であってほしい」と。
 ただし、Unload にともない、実際のオブジェクトの消滅とは別に、ichinoseさんも指摘される、Teriminate機能で
 そのユーザーフォーム内の「何らかの設定」は初期化される。それが、上でアップしたテストコードでいえば
 たとえば Tag の参照ができなくなるような。これは、「そう思い込みたい」というものかもしれませんが。

 私が期待する前者であれば、メモリー内に、「正規オブジェクト」として存在するわけだから、仮に、そのあと
 Show をかけても、Initialize は実行されないはずですが、

 UserForm3 を準備し

 Private Sub UserForm_Initialize()
    MsgBox "Hello"
 End Sub

 Private Sub UserForm_Activate()
    Unload Me
 End Sub

 で、標準モジュールに

 Sub Test3_1()
    With UserForm3
        .Show
        UserForm3.Show
    End With
 End Sub

 Sub Test3_2()
    With UserForm3
        .Show
        .Show
    End With
 End Sub

 この結果は、Test3_1 は正常終了、しかしながらメッセージが2回、つまり、2回目もInitialize実行。
 まぁ、これは、ユーザーフォームが特殊で UserForm3.Show が、裏で New UserForm3 としてSetされた
 別物の UserForm3 なんだろうと、これも、無理やり思い込もうと。
 一方、Test3_2 は 2回目の .SHow でオートメーションエラー。

 ★結局よくわからないのですが、経験上、「通常のユーザーフォーム配下のコントロールの参照はできている」
 この1点を頼りに、使用を続けています。

 (ぶらっと)


 >Sub Test3_2()
 >   With UserForm3
 >       .Show
 >       .Show
 >   End With
 >End Sub
 これは、Withで、UserForm3をとっ捕まえた状態なので、
 End Withを抜けるまでは....。
 >別物の UserForm3 なんだろうと
 こうはならないと思う。
 BJ

 To BJ さん

 >別物の UserForm3 なんだろうと

 こう理解しているのは、参照された Test3_2 ではなく、Test3_1 のほうです。

 (ぶらっと)


 え〜と、Test3_1の方はそんな感じでといった意味を含ませたつもりだったのだけれど。
 でも、End Withを抜けるまでは....。とは、ちょっと筋が違いますよね。
 う〜ん。
 解放のタイミングなのか??
 BJ

 >一番簡便な方法はパブリック変数による受け渡しですが
 この例題で言うUserForm2というオブジェクトは、出力先を限定したくないということから、
 再利用を簡単にしたいオブジェクトですよね?

 将来、対象ブックだけでなく、他のブックでも使えるような色んな事案に対処できるような
 再利用可能なオブジェクトになる可能性を秘めているかもしれない。
 そこまで押し上げるためには、ここで仰っているパブリック変数というのが、標準モジュールに
 宣言する変数だとしたら、記述は簡単なかもしれませんが、使いやすいオブジェクト、つまり、道具には
 ならないと思いますよ!! UserForm2というオブジェクトのデータの受け渡しがパブリック変数を使うことで
 結合度の強いオブジェクトになってしまいますしね!!

 私も持っていますよ カレンダー用のフォーム
 集計期間等で日付指定を行う場合、ボタンでカレンダーが表示されこれで日付を指定する機能
 日付指定って、よく使う処理ですからね

 私は、アドインにしています。アドインからUserformのインスタンスだけ受け取って、

 Private Sub CommandButton1_Click()
    Dim frm As Object
    Set frm = Workbooks("selectdate.xla").frmdate 'アドインからUserformのインスタンスを受け取る
    With frm
       .Show
       TextBox1.Value = Format(.sdate, "yyyy/m/d") 'sdateは、選択した日付
    End With
    Unload frm 'オブジェクトの消去
 End Sub

 インターフェースを工夫すれば、呼び出すだけですよね?

 対象Userformからの戻り方を Unload me を見たことによって、
 体験できた様々な現象は、興味深いものだったのですが、

 ここで体験できた不可解なエラーも
 戻り方を me.hideにすることで

 エラーにはなりません。
 また、出力媒体にテキストボックスを介さずとも、普通に
 Private変数に保持し、Property get 辺りで取得できます。

 将来の機能拡張も考慮する(メソッドを追加したいなんて時)とやはり、より確実なのは Hideだと思います!!

 (因みに

 Unload me

 でも

 Userform2に

 Public aaa as long

 のような変数は、値の取得が出来ました。

 但し、

 Public aaa as string  と型を変更すると値の保持は出来ませんでした。

 これは、何となく納得できましたが・・・。
 Stringの場合、実際のデータは、別の場所ですからねえ)

 ichinose


To ichinoseさん

いただいた事例による2010でのテストはまだ行っていません。
ただ、私がアップしたテストコードで2003でオートメーションエラーになったもの(.Tag)については
2010では、エラーにはならず、ただし、値は空白。

 >そこまで押し上げるためには、ここで仰っているパブリック変数というのが、標準モジュールに
 >宣言する変数だとしたら、記述は簡単なかもしれませんが、使いやすいオブジェクト、つまり、道具には
 >ならないと思いますよ!! 

 全く同感です。
 ですので「呼び出しフォームと共通フォームの当事者間だけのスコープに しておきたく」と書きましたように
 今回の対応策としては提示しませんでした。

 なお、

 >ここで体験できた不可解なエラーも
 >戻り方を me.hideにすることで
 >エラーにはなりません。
 >また、出力媒体にテキストボックスを介さずとも、普通に
 >Private変数に保持し、Property get 辺りで取得できます。

 これは、あるいみあたりまえですね(失礼)
 たんに非表示になっているだけでフォームはメモリ上でいきているわけですから。
 わたしがUnload にしたのは、すでに上で書かせていただいたような意味なんですが、
 Hideでやれるなら、それにこしたことはないですね。

 (ぶらっと)

 >2010では、エラーにはならず、ただし、値は空白

 記述が曖昧でした。

 >Public aaa as string  と型を変更すると値の保持は出来ませんでした。

 これも呼び出し側では、エラーにはなりませんでした。

 値は空白です。

 ichinose

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.