Form2で宣言したFunctionという名前の関数をForm1で使いたい場合にはどのようにすればよいでしょうか?
Form1で"Public Form2 As New Form2"として宣言したら、Form1からForm2.Functionと呼び出して使えたました。しかし、Form2を閉じてもう一度表示させようとすると、"破棄したオブジェクトにアクセスできません。"とエラーが出ました。
プログラムは『電卓』の設計図のようなもの。
>Form1で"Public Form2 As New Form2"として宣言したら、Form1からForm2.Functionと呼び出して使えたました。
これは Form2 の設計図から実際に使える『電卓』を組み立てたようなもの。
その手続きが New で、実際はメモリに変数の領域を確保したり初期化したりするわけです。
>Form2を閉じてもう一度表示させようとすると、"破棄したオブジェクトにアクセスできません。"とエラーが出ました。
Form2 を閉じるという事は実物の『電卓』を捨ててメモリを開放するということです。
実物(オブジェクト)はもうありませんから当然アクセスできません。
設計図は残ってますが、設計図に書かれた『電卓』に計算させようとしても、これまた当然できません。
解決するには
案1:もう一度使える『電卓』を組み立てる(Form2 を New する)
案2:Form2 以外の場所に関数を移動させる。(当然メモリに確保されたら破棄しない場所に)
案3:Form2 を閉じる処理で Form2 を破棄せず非表示にする
などがあります。…ちなみにこの質問は[VB.NET]?環境も書いてね?。それによって回答が変わってくるから。
環境はVB.NETです。
>案1:もう一度使える『電卓』を組み立てる(Form2 を New する)
は試そうとしました。ただ、やり方が間違っていたのだと思うのですが、
Form2.show()
でForm2を表示させる直前に
Dim Form2 As New Form2
としてもForm2の関数が使えていないようでした。
なんとなくこれでは駄目なのはわかったんですが、どうしたら良いのかが
わからず質問した次第です。
なので、
>案3:Form2 を閉じる処理で Form2 を破棄せず非表示にする
で解決することにしました。
ありがとうございました。
できれば、案1の正しい方法も教えていただけますか?
よろしくお願いいたします。
>Form2.show()
>でForm2を表示させる直前に
>Dim Form2 As New Form2
>としてもForm2の関数が使えていないようでした。
いいえ、間違っていません。
フォームもクラスです。New も(特殊ではあるものの)関数です。
New した時点で関数は使えてると言っても過言ではありません。
[VB.NET2003]
'///////////// Form1 のコード Start
Option Explicit On
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
' 省略
#End Region
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ChildForm As New Form2()
With ChildForm
.Show()
.MessageBoxShow()
End With
End Sub
End Class
'///////////// Form1 のコード End
'///////////// Form2 のコード Start
Option Explicit On
Public Class Form2
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
' 省略
#End Region
Public Function MessageBoxShow()
MessageBox.Show("メッセージ")
End Function
End Class
'///////////// Form2 のコード End
上記の方法で、仮にButton2_Clickイベントを追加して、そこからButton1_Clickイベントで呼び出したChildFormにはアクセスできませんよね?
やりたかったことは、Form2のテキストボックスにForm1から
書き込みをすることです。
その際、Form1のどのイベントからでもForm2の同じテキストボックスに
書き込むために以下のようにしました。
これだと、Form2を閉じたときにChildFormが指していたオブジェクトが
破棄されるので失敗するという風に理解したのですが、私の理解は
間違っているのでしょうか?。
[VB.NET2003]
'///////////// Form1 のコード Start
Option Explicit On
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
' 省略
#End Region
Public ChildForm As Form2
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
With ChildForm
.Show()
.InputText("1")
End With
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
With ChildForm
.Show()
.InputText("2")
End With
End Sub
End Class
'///////////// Form1 のコード End
'///////////// Form2 のコード Start
Option Explicit On
Public Class Form2
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
' 省略
#End Region
Public Function InputText(Byval s As String)
TextBox1.Text &= s
End Function
End Class
'///////////// Form2 のコード End
ええ、間違ってないと思います。
通常、New する前の Form を参照する変数に何が入ってるか調べましたか?。
インスタンスは生成されておらず、参照先は指定されていないので Nothing
となっているはずです。New した時点でメモリ上に実体化したフォームの
アドレスを参照することとなります。
ここでフォームが破棄された場合、システムが関連して使用していた変数が
利用していたメモリは全て開放されます。ところが ChildForm のように
こちらが用意した変数は自動で開放されません。従って、過去フォームが
あったアドレスを参照しようとして問題が起こるわけです。フォームが破棄
された時点で
ChildForm = Nothing
とし、ChildForm が Nothing かどうかを判断して New するか、過去作成した
(破棄されてない)フォームで処理を実行するか判断してください。
あ、それと
>>案3:Form2 を閉じる処理で Form2 を破棄せず非表示にする
>で解決することにしました。
ということですが、この場合の注意点は『画面に表示されていないのにメモリ
上には ChildForm が生きている』ということです。
今度は、Form2 が非表示の時に Form1 を閉じたとします。
…どうなりますか?。
画面上に見えない(ユーザが操作できない) Form2 がずっと残ることとなります。
Form1 を破棄する時点で Form2 を破棄することを忘れないで下さい。
こういったお互いを参照する変数を持つプログラムは、破棄したときに連携を
取っておかないといけません。これはエクセルを参照する時などでも有名な話です。
非常に丁寧な説明でわかりやすかったです。
ありがとうございました。
ツイート | ![]() |