11

以下は私が自分で答える質問ですが、それは私にとって大きな欲求不満を引き起こし、ウェブで検索するのに苦労したので、他の人のために時間と労力を節約することを期待してここに投稿しています.将来これを忘れた場合、おそらく自分自身のために:

VBA(私の場合はMS Excel)の場合、Public宣言は、変数(または関数)をそのモジュール内の他の関数またはサブルーチンからグローバルにアクセスできるようにすることになっています。他のモジュール。

Forms
Sheets. _ _

要するに、以下は、で作成されたときにパブリックでアクセス可能な変数を作成しません。Formしたがって、mModule1 で bYesNo 変数と dRate 変数が未定義であると言ってクラッシュします。

(inside fMyForm)
Public bYesNo As Boolean`
Public dRate As Double

Private Sub SetVals()
    bYesNo = Me.cbShouldIHaveADrink.value
    dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
(Presume the textbox & checkbox are defined in the form)

(inside mModule1)
Private Sub PrintVals()
    Debug.Print CStr(bYesNo)
    Debug.Print CStr(dRate)
End Sub


ただし、以下のわずかな変更を加えると、すべて正常に機能します。

(inside fMyForm)

Private Sub SetVals()
    bYesNo = Me.cbShouldIHaveADrink.value
    dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
(Presume the textbox & checkbox are defined in the form)

(inside mModule1)
Public bYesNo As Boolean`
Public dRate As Double
Private Sub PrintVals()
    Debug.Print CStr(bYesNo)
    Debug.Print CStr(dRate)
End Sub


mModule1fMyForm が常に最初に呼び出されると仮定すると、PrintValsルーチンが実行されるまでに、フォームのテキストボックスとチェックボックスの値が適切にキャプチャされます。

正直なところ、MS がこの変更で何を考えていたのかを理解することはできませんが、一貫性の欠如は効率を大きく損ない、このような特異性を学習します。 10年以上を検索するのは非常に困難です。

4

2 に答える 2

4

最初のコメント:

ユーザーフォームとシート モジュールはオブジェクト モジュールです。通常のモジュールと同じようには動作しません。ただし、クラス プロパティを参照する方法と同様の方法で、ユーザー フォーム内の変数を参照できます。あなたの例では、 fMyForm.bYesNo を参照するとうまくいきます。bYesNo を Public として宣言しなかった場合、フォームの外部のコードからは見えないため、Public にすると、実際には非 Public とは異なります。— ティム ウィリアムズ

実際には正しい答えです...

于 2015-11-30T15:03:19.380 に答える
1

コミュニティの回答に対する簡単なアドオンの回答として、念のため:

フォームをインスタンス化するときは、フォーム オブジェクト自体を使用するか、New を使用して変数に入れることにより、フォーム オブジェクトの新しいインスタンスを作成できます。後者の方法はよりクリーンな IMO です。

ただし、ユーザーフォームで Unload(Me) を呼び出すと、すべてのパブリックメンバーが消去されます。したがって、コードが次のようになる場合:

  Dim oForm as frmWhatever
  Set oForm = New frmWhatever
  Call oForm.Show(vbModal)
  If Not oForm.bCancelled Then  ' <- poof - bCancelled is wiped clean at this point

これを防ぐために私が使用するソリューションは、OP にとっても優れた代替ソリューションです。すべての IO をフォーム (つまり、すべてのパブリック メンバー) で別のクラスにキャプチャし、そのクラスのインスタンスを使用して通信します。フォーム。だから、例えば

  Dim oFormResult As CWhateverResult
  Set oFormResult = New CWhateverResult
  Dim oForm as frmWhatever
  Set oForm = New frmWhatever
  Call oForm.Initialize(oFormResult)
  Call oForm.Show(vbModal)
  If Not oFormResult.bCancelled Then  ' <- safe
于 2016-01-18T10:03:09.773 に答える