- ベストアンサー
変数の扱いについて
こんにちは。お世話になります。 ユーザーフォームモジュールで宣言した変数を標準モジュールのサブプロシージャ内で使うには どのようにしたらよいのでしょうか? ====== ユーザーフォームモジュール ======= Dim MyData1 as Long Dim MyData2 as Long Private Sub CommandButton1_Click() For MyData1 = 1 To 10 MyData2 = MyData1 * 2 Call test1 Call test2 Next MyData1 End Sub ====== 標準モジュール ======= Sub test1() Worksheets("Sheet1").Range("A" & MyData1).value = MyData2 * MyData2 End Sub Sub test2() Worksheets("Sheet2").Range("A" & MyData1).value = MyData2 + MyData2 End Sub For~Nextは標準モジュール内ではなくユーザーフォームモジュール内に作りたいのです。 おわかりの方よろしくお願いしますm(_ _)m
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
taocat様、suffre様 あまり、VBAの一般論まで発展してしまうと、私自身混乱してしまいます。(^^; 参照渡しで、サブルーチン側のTest1に、引数のMyData1を変更するコードが入っているなら理解できるのですが、引数のMyData1を変更していくなら、逆に、明示的なByVal キーワードは無意味になってしまいます。 実際の設計では、私は、従属的なサブルーチンはローカルに、それも、Private にして、同じモジュールの中に入れています。 そういう点で、今回、#5 のStudyVBAさんが、ご指摘のように、確かに、ByVal キーワードを使ったほうが正解だったかもしれませんが、もともと、値渡し・参照渡しの キーワードをサブルーチン側につけるつけないというよりも、標準的には、参照渡しになっていまから、値渡しにすべきかは、コードの設計の趣旨の問題だと思います。 逆の見方をすると、メイン側から渡された引数が、値渡しのキーワードをつけないサブルーチン側で、引数の値を変更して、メインに戻ってきても、それが保持されているということなら、変数としての役割も、またシステム全体のコードとしての論理も適っていることだと思います。 何か、とっても難しい書き方になっていますが、つまり、キャッチボールをしていて、投げられた玉を、相手が、ボールに細工をして返してきても、そのまま受け取って、また使うのが参照渡しです。相手がボールを別のにすりかえても、ボールの大きさ(変数型)は変えられないので、使い続けます。 投げられたボールを、相手が細工して返してきたボールは受け取らず、次に、別の自分のボールを使うのが、値渡しっていうことかな?
その他の回答 (7)
- taocat
- ベストアンサー率61% (191/310)
再度のこんにちは。 suffreさん、こんにちは。 Wendy02さん、いつも丁寧なレスありがとうございます。 suffreさんのNo.6、Wendy02さんへのお礼のコメントが気になりましたので再度の書きこみです。 ---------------------------------------------- >でも、今回の場合は、 > For MyData1 = 1 To 10 >となっていますから、参照渡ししようとしても出来ないと思います。 そうかあ!Callで読んできて変数の値が変更されていてもNextでForに戻ればMyData1とMyData2は値が代入されてしまうので参照渡しの意味はなくなるということですね。 ----------------------------------------------- それは変数MyData2にだけ言えることです。先の回答にも書きましたが、変数MyData1については上記のことは言えません。 もし参照渡しをしていて、Test1側でMyData1が55に変更されたとしたら、Mainに戻っていったとき For MyData1=1 to 10 MyData1は55になってますので、このFor文は抜けてしますわけです。 それより危険なのは、Mydata1が、1~9までに変更された場合です。 上記For文は無限ループになります。 試しに、Test1側で、 MyData1を 2 に変更 MyData1を 55 に変更 これでテストしてみてください。ご理解いただけると思います。 尚,コメントの意味を取り違えていましたら、VBA勉強中ということでご容赦願います。
- Wendy02
- ベストアンサー率57% (3570/6232)
StudyVBA様へ 私も、そんなキャリアがあるわけではありませんが、一応、私のハンドルがあったので、付け足しておきます。 >今回の場合はその危険はないでしょうが、引数を使う場合、値渡し、参照渡しに常に気を配るようにするべきだと思います。 # Sub test1(ByVal MyData1 As Long, ByVal MyData2 As Long) 後で、その使い方を忘れてしまったりするような場合に、特定の引数の渡し方を、サブルーチン側に「明示的に」入れておいたほうがよいでしょうね。 ふつうは、引数を渡す側のコードの問題だから、あまり、私は、ユーザー定義関数のように重要視していません。(間違っているのかもしれませんが) でも、今回の場合は、 For MyData1 = 1 To 10 となっていますから、参照渡ししようとしても出来ないと思います。
- StudyVBA
- ベストアンサー率0% (0/3)
こんにちは。 まだ回答するレベルではないのですが、序に頭に入れておいた方がいいと思いましたので一言。 サブルーチンTest1,2側ですが、少なくともMyData1はキーワードByValで値渡しにすべきではないでしょうか。 ByValなしだと参照渡し(ByRef)になりますので、サブルーチンTest1,2側で、変数Mydata1,MyData2の値を変えてしまうことができるので思わぬ結果を招くことになります。 今回の場合はその危険はないでしょうが、引数を使う場合、値渡し、参照渡しに常に気を配るようにするべきだと思います。 ---------------------------------------------- Sub test1(ByVal MyData1 As Long, ByVal MyData2 As Long) End Sub ---------------------------------------------- Wendy02さん、これ間違いないですよね?・(^^;;;
お礼
StudyVBAさんこんにちは! 参照渡しと値渡しがあるんですね。これも大事典で調べてみました。 図解つきでとてもわかりやすかったです。 ByValだと標準モジュールで変更された変数の値はユーザーフォームモジュールには戻されないということですね。 これも勉強になりました。ありがとうございます!
- Wendy02
- ベストアンサー率57% (3570/6232)
suffreさん、こんにちは。 変数を共通で使う場合は、Public ステートメントを使ってもよいのですが、コードをみる限りでは、変数の保持の必要性がありません。実際に、システムとして作っていくと、Public スコープの変数は、意外に取り扱いが面倒なのです。本当に、Publicレベルなのか、という使い分けには慎重にならざるを得ない時があります。今時点の正解は、Publicステートメントであっても、どこか、記憶の片隅に入れておいてください。 Private Sub CommandButton1_Click() Dim MyData1 As Long Dim MyData2 As Long For MyData1 = 1 To 10 MyData2 = MyData1 * 2 Call test1(MyData1, MyData2) Call test2(MyData1, MyData2) Next MyData1 End Sub Sub test1(MyData1 As Long, MyData2 As Long) Worksheets("Sheet1").Range("A" & MyData1).Value = MyData2 * MyData2 End Sub Sub test2(MyData1 As Long, MyData2 As Long) Worksheets("Sheet2").Range("A" & MyData1).Value = MyData2 + MyData2 End Sub
お礼
Wendy02さんいつもお世話になっています! >実際に、システムとして作っていくと、Public スコープの変数は、意外に取り扱いが面倒なのです。 そうなのですか・・・。私にはまだわからない領域かもしれませんね。Publicの方法もあるということは勉強になりましたが引数渡しのほうがよいのですね。 たとえば変数が増えていくと下記のカッコ内にもどんどん書き込んでいくことになるのでしょうか? Sub test1(MyData1 As Long, MyData2 As Long, MyData3 As Long, MyData4 As Long, MyData5 As Long, ・・・) 現在使いたい変数は4つなのですが、変数が大量になった場合の記述はどうなのかなって思いまして・・・。
- pascal3141
- ベストアンサー率36% (99/269)
#1さんの解答にあるように、引数をつけて呼び出すのがよいと思います。(次のように)標準モジュールにPublic定義をする方法は、別の場所で同じようなものを使ったとき変数が変わってしまう場合があり、私も以前これでエラーを見つけるのに時間がかかりました。できるだけその場所でしか変数が使われないようにする方がミスが少なくなります。 ====== ユーザーフォームモジュール ======= 省略 Call test1(MyData1, MyData2) Call test2(MyData1, MyData2) 省略 End Sub ====== 標準モジュール ======= Sub test1(D1 As Long, D2 As Long) Worksheets("Sheet1").Range("A" & D1).Value = D2 * D2 End Sub Sub test2(D1 As Long, D2 As Long) Worksheets("Sheet2").Range("A" & D1).Value = D2 + D2 End Sub
お礼
pascal3141さんお返事ありがとうございます。 引数を使う方法とPublic宣言する方法があるのですね。 Excel大事典で引数を使う方法を探してみると・・・プロシージャの連携というやつですね。 この場合の宣言はユーザーフォームモジュール内でDim宣言でいいのですかね・・・。できなかったらPublicにすればいいかな。
- tinu 2000(@tinu2000)
- ベストアンサー率40% (147/366)
====== ユーザーフォームモジュール ======= Private Sub CommandButton1_Click() For MyData1 = 1 To 10 MyData2 = MyData1 * 2 Call test1 Call test2 Next MyData1 End Sub ====== 標準モジュール ======= Public MyData1 As Long 'ここにpublicで Public MyData2 As Long 'ここにpublicで Sub test1() Worksheets("Sheet1").Range("A" & MyData1).value = MyData2 * MyData2 End Sub Sub test2() Worksheets("Sheet2").Range("A" & MyData1).value = MyData2 + MyData2 End Sub これが簡単です。
お礼
tinu2000さん詳しい記述いただきまして感謝です! Public変数は標準モジュールに記述するのですね。 Excel辞書をくまなく読んでみました・・・。 「Privateステートメントで宣言した変数はDimステートメントを使用して宣言した場合と同じで、そのモジュール内でのみ使用できます」 そうだったんですね。私のはユーザーフォームモジュールに書いてしまいました。 またひとつ勉強になりました。
- osamuy
- ベストアンサー率42% (1231/2878)
標準モジュール側関数を引数付きにするか、フォーム側の公開したい変数を(dimでなく)publicとして定義するとか。
お礼
osamuyさん、お返事ありがとうございます! Publicを使うのですね。Excel辞書を開いてみました・・・。 「すべてのモジュールのすべてのプロシージャで使えます」 これかぁ! Excel VBAを初めてまだ1週間ほどのド素人でただいま勉強中のため目が赤くなるまで辞書読んでますが1000ページは分厚いです・・・。
お礼
>でも、今回の場合は、 > For MyData1 = 1 To 10 >となっていますから、参照渡ししようとしても出来ないと思います。 そうかあ!Callで読んできて変数の値が変更されていてもNextでForに戻ればMyData1とMyData2は値が代入されてしまうので参照渡しの意味はなくなるということですね。 これは頭使いますね・・・勉強になりました!