プロが教えるわが家の防犯対策術!

先日、Excelvba2013の質問で、フォームへの変数の引き継ぎのコードを教えていただきましたが、まだ理解が乏しく、もう少し追加で質問させて下さい。
標準モジュールから最初のユーザーフォームtest1を呼び出し、CommandButton1をクリックしてさらに別のユーザーフォームtest2を呼び出し、test1で使用していた変数をそのまま使いたいのですが、標準モジュールにPublicで宣言すると使えるという方法があるそうですが、その方法を使いたくない場合の方法として、Public Property Let というのを教えていただきました。
試した所、変数mValue2 の元の中身であるUBound(mydicKey)は、フォーム2のどこからでも使用できるようになりました。しかし、残りの変数Call test2.FormInit(ws, myDic, mydicKey, mydicitem, row)でフォーム2へ渡したものは、フォーム2のPublic Sub FormInit内のみでしか使用できず値が消えていました。
他のもフォーム2内のどこでも使用するにはどうすればよいのでしょうか?他のもPublic Property Letを使ってセットしようとしましたが、うまくいきませんでした。今回も標準モジュールにPublicで宣言する方法は、なしでお願いします。
全てで使える方法以外でも、フォーム2のPublic Sub FormInitから任意のプロシージャのみに引き渡す方法もあるのでしょうか?(例えばフォーム2のPublic Sub FormInitからフォーム2のPrivate Sub TextBox1_Changeのみへ変数rowを引き継ぐような方法)
また、Public Property Letがこの中でどんなふうな役割をしているのかもご教授いただけるとありがたいです。
どうぞ、よろしくお願いいたします。


★★★標準モジュール記載
Public Sub ShowForm()
Load test1
test1.Show vbModeless
End Sub

★★★フォーム1つ目(test1)
Dim ws As Worksheet
Dim myDic As Object
Dim mydicKey As Variant
Dim mydicitem As Variant
Dim row As Long
Dim c As Range

Private Sub UserForm_Initialize()
Dim i As Long
Set ws = ThisWorkbook.ActiveSheet
Set myDic = Nothing
Set myDic = CreateObject("Scripting.dictionary")
Call 別モジュール.mydic_set(ws, myDic, mydicKey, mydicitem, row)
With ComboBox1
.ColumnCount = 2
.TextColumn = 2
For i = LBound(mydicKey) To UBound(mydicKey)
.AddItem ""
.List(i, 0) = mydicKey(i)
.List(i, 1) = ws.Range(mydicitem(i)).Offset(1, 0)
Next i
End With
End Sub

Private Sub CommandButton1_Click()
Me.Hide
Load test2

test2.Value2 = UBound(mydicKey)
Call test2.FormInit(ws, myDic, mydicKey, mydicitem, row)

test2.Show vbModeless
End Sub

★★★フォーム2つ目(test2)test1から呼び出し
Privete mValue2 As Long

Public Property Let Value2(ByVal Value1 As Long)
mValue2 = Value1
End Property

Public Sub FormInit(ByVal ws As Worksheet, myDic As Object, mydicKey As Variant, mydicitem As Variant, row As Long)
Label1.Caption = mValue2
End Sub

Private Sub TextBox1_Change()
Label1.Caption = mValue2
End Sub


★★★フォーム1のサブモジュール
Function mydic_set(ByVal ws As Worksheet, myDic As Object, mydicKey As Variant, mydicitem As Variant, row As Long)
Dim c As Range
row = ws.Range("B" & Rows.Count).End(xlUp).Row
For Each c In ws.Range(ws.Cells(1, 2), ws.Cells(row, 2))
If c.Value Like "*番" Then
myDic.Add c.Value, c.Address
End If
Next c
mydicKey = myDic.Keys
mydicitem = myDic.Items
End Function

質問者からの補足コメント

  • うーん・・・

    うーん、ちょっと難しく使いこなせていません。

    Private Sub CommandButton1_Click()
    Me.Hide
    Load test2
    test2.Value2 = UBound(mydicKey)
    Call test2.FormInit(ws, myDic, mydicKey, mydicitem, row)
    test2.Show vbModeless
    Label1.Caption = mValue2
    End Sub
    mValue2に値が入っているのは確認できるのですが、上記のようにフォーム2の処理が終わり、フォーム1に戻った直後の処理の中(Label1.Caption = mValue2)では、中身が入っていません。
    別の処理を行うと値が確認できます。
    どうしたら、戻った直後の処理で変数mValue2を使えますか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2019/03/17 20:15
  • うーん・・・

    すみません。先ほどの補足は勘違いしていました。test2.Show vbModelessのあと、別フォームの処理にとんで、戻って続きを処理すると思っていましたが、違いました。よって、Label1.Captionの所は、フォーム2の方で操作すればできました。お騒がせしました。忘れて下さい。

    最初の回答の中の話は、LetがあってGetで取得という感じで使用するのでしょうか?
    以前別の質問の時、教えていただいた回答ではLetのみを使用して別フォームに引き渡していました。その辺りが今一結びつきません。調べても、教えていただいたようなやり方の記事もあまり出てこないので・・・。
    その辺りを、もう少しご教授いただけないでしょうか?
    お手数をおかけいたしますが、よろしくお願いいたします。

      補足日時:2019/03/18 00:02
  • test2のmValue2が消えていた、とかその辺りの処理はできました。

    もう少し教えていただきたいのは、今回提示したコードは、Public Property Letのみ使用してGetの方は使用していないのですが、ユーザーフォーム1の値である、UBound(mydicKey) をユーザーフォーム2内で使用できます。Public Property Letの処理で mValue2の中の値を入れているのだと思いますが、今回の説明の最後にある、「〇〇=test2.Value2」というコマンドのよって、「Public Property Get Value2」プロシージャが起動して、という所ですが、このコードに「Public Property Get Value2」というプロシージャは存在していないのですが、mValue2 という入れ物に入っています。そこは、どう考えればよいのでしょうか。

    No.2の回答に寄せられた補足コメントです。 補足日時:2019/03/19 22:14

A 回答 (3件)

>Public Property Letのみ使用してGetの方は使用していないのですが、ユーザーフォーム1の値である、UBound(mydicKey) をユーザーフォーム2内で使用できます。


再度書きますが、コード「test2.Value2 = UBound(mydicKey)」を実行した時点で
test2側に記述されたプロシージャー「Public Property Let Value2(ByVal Value1 As Long)」が起動し、mValue2へ値が渡されます。このmValue2はPublic Property Let の外(test2内では共通)で定義されたものですので、test2が破棄(UesrFormではUnloadなど)されるまで保持されるのです。
(もし中で定義されていれば、そのプロシージャが終了した時にその変数は破棄されます。)
つまり、test2が破棄されるまでは、その中の別のプロシージャーでは共通の値として使用できます。
また、この値を他のモジュールから参照する場合に必要なのが、「Public Property Get Value2」で「○○=test2.Value2」というコードの時に起動することになります。
勿論、test2内の別のプロシージャーで「〇〇=Value2」というコードでも起動しますが、ここではmValue2を直接参照できますのであまり意味はありません。
実はもっと多彩な使い方があるのですが、クラスモジュールに関する事項を参考にすれば良いと思います。実はUserFormは標準で準備されたクラスモジュールなのです。
    • good
    • 0
この回答へのお礼

ありがとうございます。理解の助けになりました。

お礼日時:2019/03/21 02:15

内容がややこしいので正確に把握できていない点をご了承願います。


基本的に、test2(UserForm?)内で変数定義した物は他から参照できません。
(他から、むやみに変更されたくない変数などに使用するものです)
それを容易にするためにPublic(公開する)変数が存在するのですが、それを使いたくないようです。
そこでPublic Property Let/Getの出番になります。
簡潔に言えば、「Property Let (引数)」で「変数に引数を代入する」、「Property Get()」で「変数の値を引き出す」といったところでしょうか。ですから、
>最初の回答の中の話は、LetがあってGetで取得という感じで使用するのでしょうか?
という認識で問題ないと思います。
このように、外部からの「変数を引数の値にして」や「変数の値をください」という命令を公に使える(他のモジュールで使える)ようにしているのです。
勿論、Private Property Let/Getも存在し、これらは外部から使用することはできません。

「test2のmValue2が消えていた」ということですが、先に
test2.Value2 = UBound(mydicKey)
が確実に処理されていますでしょうか?
※この処理によりtest2の「Public Property Let Value2(引数)」プロシージャが処理され、mValue2の値が入力されます。
その後、「〇〇=test2.Value2」というコマンドのよって、「Public Property Get Value2」プロシージャが起動して「test2.Value2(test2での変数名はmValue2)」がかえって来るのです。
この回答への補足あり
    • good
    • 0

>残りの変数Call test2.FormInit(ws, myDic, mydicKey, mydicitem, row)でフォーム2へ渡したものは、


>フォーム2のPublic Sub FormInit内のみでしか使用できず値が消えていました。

Sub FormInit の外に変数宣言をして、
Sub FormInit の中で必要なものすべて転記します。

Property は次のように Get/Let をペアで使うとあたかも
Value2 という Public 変数のように使えます。
Dim mValue2 As Long
Public Property Get Value2() As Long
Value2 = mValue2
End Property
Public Property Let Value2(ByVal Value1 As Long)
mValue2 = Value1
End Property

同様に、Property には Get/Set をペアで使うのもあります。
こちらは、オブジェクト変数に使います。

単純な変数なら、フォーム上にテキストボックスを作ってそれを直接使うというのもあります。
変数の値が常に見えてるのでデバッグ中はとても便利です。
本番移行の際は、これらの Visible プロパティを False にすれば、
ロジックは変更する必要がありません。
この Visible プロパティをもれなく変更するには、
条件付きコンパイル引数を使うのが確実です。
興味があったら検索してみてください。
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A