トップ回答者
フォーム1の配列のデータをフォーム2に渡したい

質問
-
フォーム1で用いている配列のデータ<x1()>をフォーム2に渡したいのですが実行すると、「System.NullReferenceException
オブジェクト参照がオブジェクト インスタンスに設定されていません。」といったエラーが出ます。何が問題なのでしょうか。ソースは以下の通りです。
<フォーム1>
Public Class Form1
Private Shared _form1Instance As Form1
Public Shared Property Form1Instance() As Form1
Get
Return _form1Instance
End Get
Set(value As Form1)
_form1Instance = value
End Set
End Property~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
x1()を用いる計算プログラム
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Shared x1 As Double()
Public Property Gurahux1 As Double()
Get
Return x1
End Get
Set(ByVal value() As Double)
x1 = value
End Set
End Property
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Hide()
Form2.ShowDialog()
Show()
End SubEnd Class
<フォーム2>
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.LoadF2TB1.Text = Form1.Form1Instance.Gurahux1(0)
End SubEnd Class
(今回はテキストボックスに配列の最初の数値だけ入れるという動きにしています)
お忙しいとは思いますがなにか助言等いただければ幸いです。
回答
-
おんやさい252 さま よろしく。
単に、Form1 に Button2、Form2 に TextBox F2TB1 を置いただけで、
Form1 の以下のコードでは如何ですか?。Public Class Form1
Friend x1s As Double() = {1.0, 2.0, 3.0}
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
x1s(0) = 1.5
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'Dim x1s As Double() = {1.0, 2.0, 3.0}
Dim f2 As New Form2
f2.F2TB1.Text = x1s(0)
f2.ShowDialog()
End Sub
End Class一方通行で渡すだけなら、Form2 に記述は不要です。
- 編集済み ShiroYuki_Mot 2019年1月19日 14:51 コード変更 値はきっと何処かで処理の筈
- 回答としてマーク おんやさい252 2019年1月20日 12:08
すべての返信
-
プログラムのどこでNullReferenceExceptionが発生しているかわかりますか? また、 NullReferenceExceptionの意味はご理解されてますか?
ざっとプログラムを拝見したところ配列X1をどう渡すか、ということとは別の問題としてNullReferenceExceptionが発生しているんじゃないかと疑います・・・。Form2.ShowDialog()のところなのですが・・・。
Instanceの文字があるので「インスタンス」の意味はご理解されているかも? と拝察しますが・・・、プログラム実行時にクラスForm1、クラスForm2、クラスDouble()つまりDouble配列のX1、いずれもインスタンスを作るためのNewキーワードがプログラムに見当たらず、NullReferenceExceptionが発生する可能性がいろいろ考えられます。
ただ、今のVisual BasicはクラスFormから派生させた場合、クラスを宣言するだけでインスタンスが生成される仕組みがあるらしいので、細かいところは質問者さんのプログラミングされている環境の設定次第ではあるのですが。
- 編集済み 外池 2019年1月19日 9:44
-
外池さん返信ありがとうございます!
エラーはフォーム2の「F2TB1.Text = Form1.Form1Instance.Gurahux1(0)」で出てきました。NullReferenceExceptionはネットで軽く調べただけなのですが、戻り値がnullの場合にこのようなエラーが出るという認識です。
F2TB1.Text = Form1.Form1Instance.Gurahux1(0)の部分を消し、フォーム2を表示するだけなら問題なくできました。
率直に申しますと、propertyや二つ目のフォームの表示なども含めネットで調べた断片的な情報をもとにプログラムを組んでいくのが主なので根本的なことはあまり理解していないというのが現状です、、、、
-
Visual Basicは、簡略化したプログラムの書き方が出来てしまって、遭遇されたNullReferenceExceptionの意味をご説明することがかえって難しくなってしまうことがあって・・・、上手く伝わるかどうか不安ですが、以下参考にして下さい。
ーーーーーー面倒なら読み飛ばして下さい(始まり)ーーーーーー
Public Class Form1から始まってEnd Classまでのプログラム、あとPublic Class Form2から始まってEnd Classまでのプログラム、それぞれはForm1というクラスとForm2というクラスを定義しています。「クラス」とは部品の型番のようなもので「定義している」というのは、設計図を描いた、というような意味です。
Form1もForm2も画面上に表示できる部品で、表示させてみるとウィンドウの姿をしている、ということはご存知だと思います。Form1という型番のウィンドウを同時にいくつも表示させることができますし、Form2という型番のウィンドウを同時にいくつも表示させることができます。ひとつひとつのウィンドウがインスタンスと呼ばれるもので、「インスタンス」はある型番の部品の実物という意味になります。Form1という型番の部品つまりウィンドウを複数表示させて、それぞれ何か操作したいなら、あの実物とこの実物とあっちの実物・・・と区別して操作しないといけないわけですが、「あの」「この」「あっちの」という区別を「参照」と言います。そういう区別を記録・保持するために「変数」を用意することになります。型番つまりクラスの名称と変数の名称は本来別物なんですが・・・、Visual Basicではクラスの名称と、インスタンスへの参照を記録・保持する変数の名称を、ゴッチャにして簡略化して記述できてしまう特徴があって・・・、これって、Form1やForm2のようにFormから派生したクラスの場合だけだったかなぁ・・・。
ーーーーーー面倒なら読み飛ばして下さい(終わり)ーーーーーー
で・・・、
Private Shared x1 As Double()とありますが、これは、Double配列型というクラス(部品)のインスタンス(実物)を作ったことになっていない、ということを知っておいて下さい。配列の実物は出来ていないんです。また、x1という変数が配列そのものになるわけでもないんです。x1はゆくゆく作られるDouble配列型のインスタンス(実物)への参照を記録・保持するものであって、この一行を書いただけでは何も参照していません。これがNullReferenceExceptionが発生した理由です。参照(Reference)が何もされていない(Null)という意味です。
Sub New(x1() As Double)/F2TB1.Text = x1(0).ToString/End Subの追加は無かったことにして、
最初に投稿して頂いたプログラムに基づいて、修正すべき箇所を提案するとすれば・・・
Private Shared x1 as Double()をPrivate Shared x1 As Double()=New Double(4)と書き換えてみることです。これで、添え字番号0、1、2、3、4の5個の要素からなるDouble配列型の実物ができあがり、それへの参照がx1に格納されます。個々の箱の値へはx1(0)、x1(1)・・・、というように書いてアクセスできることはご存知だと思います。新しくDouble配列型の実物を作ったその瞬間は、全ての要素は0.0の値になっています。これはそういう仕様です。
で、プログラムを実行してみたら、Form2上のF2TB1(たぶんTextBoxと拝察)に0と表示されるんじゃないかと。
もう少しイジってみるなら、Form2.ShowDialog()の直前にx1(0)=3.14の1行を追加してみてください。
で、プログラムを実行してみたら、Form2上のF2TB1(たぶんTextBoxと拝察)に3.14と表示されるんじゃないかと。
- 編集済み 外池 2019年1月19日 12:12
-
Newというキーワードには少なくとも2つの使い方があることを知っておいてください。
「変数名=New クラス名」という使い方が1つです。クラス名(型番)の新しい実物を作って、その実物への参照を変数名に格納する、という動作になります。
もう1つは、
コンストラクタと呼ばれるもので、「Class クラス名」~「Enc Class」の間に「Sub New」~「End Sub」という書き方をする使い方です。これはクラス名(型番)の新しいインスタンス(実物)が作られる毎に最初に実行されるサブルーチンになります。
「Class クラス名」~「Enc Class」の間に「Shared Sub New」~「End Sub」と書けば、最初の最初に1回だけ実行されるサブルーチンになります。インスタンス(実物)を何個作ろうが、1回しか実行されません。
「Sub New」~「End Sub」と「Share Sub New」~「End Sub」は併記できます。
- 編集済み 外池 2019年1月19日 12:11
-
>フォーム2に以下のソースを追加したところ、フォーム1の「Form2.ShowDialog()」の部分に「非共有メンバーを参照するには、オブジェクト参照が必要です」というエラーが生じてしまいました。
> Sub New(x1() As Double)
> F2TB1.Text = x1(0).ToString
> End Sub
コードが間違っているようです。以下のようにすれば望む結果になると思います。Form1
Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim x1 As Double() = New Double(4) {} x1(0) = 12345.0 x1(1) = 67890.0 Dim f2 As Form2 = New Form2(x1) f2.ShowDialog() End Sub End Class
Form2
Public Class Form2 Public Sub New(ByVal y As Double()) InitializeComponent() F2TB1.Text = y(0).ToString() End Sub End Class
-
おんやさい252 さま よろしく。
単に、Form1 に Button2、Form2 に TextBox F2TB1 を置いただけで、
Form1 の以下のコードでは如何ですか?。Public Class Form1
Friend x1s As Double() = {1.0, 2.0, 3.0}
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
x1s(0) = 1.5
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'Dim x1s As Double() = {1.0, 2.0, 3.0}
Dim f2 As New Form2
f2.F2TB1.Text = x1s(0)
f2.ShowDialog()
End Sub
End Class一方通行で渡すだけなら、Form2 に記述は不要です。
- 編集済み ShiroYuki_Mot 2019年1月19日 14:51 コード変更 値はきっと何処かで処理の筈
- 回答としてマーク おんやさい252 2019年1月20日 12:08
-
外池さん、本当に丁寧な解説ありがとうございました。すべて読ませていただきました。
今までネットに流れているメソッドなどをただ流用して何が行われているのかもわからずに使っていました。エラー解消も同じようにやっていって解決しても「うごけばいいや」という考えで原因はわからずじまいということも多かったです。そんな僕にとって外池さんの解説は本当に勉強になりました。「オブジェクト指向はjavaやVB等で基本的かつ大事な考え方」であるというのは聞いたことがあるのですが実感せずにいました。今回はオブジェクト指向の重要性、そして知識を深めるとてもいい機会になりました。解説も参考にして問題も解決できました。本当にありがとうございました。
-
> Form2に記述しないというのは目から鱗でしたがこんな簡単な方法でうまくいって感動しました。
それが可能なのはデザイナ画面でコントロールをドラッグ&ドロップすると、そのコントロールのアクセス修飾子が Friend になるという VB.NET の Windows Forms アプリの特殊事情(?)によるものですので注意してください。
(ちなみに C# は private になります。VB.NET アプリで friend か private かどちらが適切かはいろいろ議論があるかもしれませんが、オブジェクト指向のカプセル化の観点だけから言えば private ではないかと思います)