none
最初のFormで条件分岐した後、その条件をその後のFormで保持しつづける方法 RRS feed

  • 質問

  • VisualBasic2010Express  WindowsXPを使っています。

    Form2でボタンを押すと、Form3に行き、その後ボタンを押すごとにForm3とForm4の間をループするようなプログラムを書きました。

    ここで、Form2には「あお」と書かれたボタンか、「あか」と書かれたボタンがあって、どちらを押してもForm3に行くようになっています。

    Form2で「あお」と書かれたボタンを押した場合には、Form3のLabel1には最初に「a」という文字が表示され、ボタンを押してForm4に行き、Form3に戻ってきたときには「b」という文字に変わっています。

    逆に、Form2で「あか」と書かれたボタンを押した場合には、Form3のLabel1には最初に「b」という文字が表示され、ボタンを押してForm4に行き、Form3に戻ってきたときには「a」という文字に変わっています。

    上記のようなプログラムを書きたいと思い、次のようにコードを書いてみましたが、最初にLabel1に「a」の文字も「b」の文字も出てきてくれません…これについてはブレークポイントを設置してみたところ、Label1.Text = "a"のところが最初にスルーされてしまっていましたが、どうすればスルーされないようになるのか、イベントを色々いじってみましたが分かりません…

    また、いったんForm4に行ってForm3に戻ってくると、エラーが発生します。どうやらいったん別のフォームに行くと、Form2を参照することができなくなってしまったようです。

    分かる方、どうかご教授ください。お願いします。

    [Form2のコード]

    Public Class Form2

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f2 = Me
            f3.Show()
            Label1.Text = Button1.Text
        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim f3 As New Form3
            f3.f2 = Me
            f3.Show()
            Label1.Text = Button2.Text
        End Sub
    End Class

    [Form3のコード]

    Public Class Form3
        Public Shared a As Integer
        Public f2 As Form2
        Public f4 As Form4
        Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            a = a + 1
            Label2.Text = a & "回目"

            'form2で「あお」を押したら、一回目にa、二回目にb。「あか」を押したら逆。
            If a = 1 Then
                If Me.f2.Label1.Text = "あお" Then
                    Label1.Text = "a"
                ElseIf Me.f2.Label1.Text = "あか" Then
                    Label1.Text = "b"
                End If
            ElseIf a = 2 Then
                If Me.f2.Label1.Text = "あお" Then
                    Label1.Text = "b"
                ElseIf Me.f2.Label1.Text = "あか" Then
                    Label1.Text = "a"
                End If

            End If

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f4 As New Form4
            f4.f3 = Me
            f4.Show()
        End Sub

    End Class

    [Form4のコード]

    Public Class Form4
        Public f3 As Form3
        Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f4 = Me
            f3.Show()
        End Sub
    End Class

    2012年10月20日 5:39

回答

  • 問題点が2つに分かれているので、順番に解決していきましょう。

    >> 上記のようなプログラムを書きたいと思い、次のようにコードを書いてみましたが、
    >> 最初にLabel1に「a」の文字も「b」の文字も出てきてくれません

    Form2のf3.Show()のタイミングが早すぎるのが原因です。f3.Show→f3.Loadが先に実行され、その後でラベルの書き換えが行われるので、f3.Load時にはf2.Label1のテキストがまだ代入されていません。
    ここは処理の順番を変えればOKです。

    Public Class Form2
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f2 = Me
            Label1.Text = Button1.Text
            f3.Show()
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim f3 As New Form3
            f3.f2 = Me
            Label1.Text = Button2.Text
            f3.Show()
        End Sub
    End Class
    

    次に

    >> また、いったんForm4に行ってForm3に戻ってくると、エラーが発生します。
    >> どうやらいったん別のフォームに行くと、Form2を参照することができなくなってしまったようです。

    参照できないのではなくて、Form4のButton1_Clickで『Dim f3 As New Form3』とやっていますから、ここのf3とForm4のメンバ変数として定義されたf3は別モノ(別インスタンス)になっています。
    いわば「別途新しく作られた箱」ですので、当然こちらのf2値はそのままだと空ですからNull参照エラーになります。
    新しいf3にもf2を代入してやればこのエラーは解消されます。

    Public Class Form4
        Public f3 As Form3
        Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f4 = Me
            f3.f2 = Me.f3.f2
            f3.Show()
        End Sub
    End Class
    

    で、その上で・・・
    とりあえずコードの問題点そのものを指摘したわけですが、質問の内容と併せて見るに、「オブジェクトとインスタンス」「変数のスコープ」といった、ごく基本的な重要事項が理解できていないように見受けられます。
    ここらへん説明し出すと日が暮れる(笑)んで、ご自分で調べて下さいとしか言いようが無いんですが、ちゃんと理解していないと同じような事でずっと躓くことになりかねないので、ちょっと気合い入れて勉強してみて下さい。
    何事も一朝一夕に身につくものではなく、地道な繰り返しが全体の理解へと繋がります。諦めなければいつか必ず理解に至りますから、粘り強く頑張ってください。
    • 回答としてマーク firstlilac 2012年10月20日 8:15
    2012年10月20日 7:05

すべての返信

  • 問題点が2つに分かれているので、順番に解決していきましょう。

    >> 上記のようなプログラムを書きたいと思い、次のようにコードを書いてみましたが、
    >> 最初にLabel1に「a」の文字も「b」の文字も出てきてくれません

    Form2のf3.Show()のタイミングが早すぎるのが原因です。f3.Show→f3.Loadが先に実行され、その後でラベルの書き換えが行われるので、f3.Load時にはf2.Label1のテキストがまだ代入されていません。
    ここは処理の順番を変えればOKです。

    Public Class Form2
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f2 = Me
            Label1.Text = Button1.Text
            f3.Show()
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim f3 As New Form3
            f3.f2 = Me
            Label1.Text = Button2.Text
            f3.Show()
        End Sub
    End Class
    

    次に

    >> また、いったんForm4に行ってForm3に戻ってくると、エラーが発生します。
    >> どうやらいったん別のフォームに行くと、Form2を参照することができなくなってしまったようです。

    参照できないのではなくて、Form4のButton1_Clickで『Dim f3 As New Form3』とやっていますから、ここのf3とForm4のメンバ変数として定義されたf3は別モノ(別インスタンス)になっています。
    いわば「別途新しく作られた箱」ですので、当然こちらのf2値はそのままだと空ですからNull参照エラーになります。
    新しいf3にもf2を代入してやればこのエラーは解消されます。

    Public Class Form4
        Public f3 As Form3
        Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f4 = Me
            f3.f2 = Me.f3.f2
            f3.Show()
        End Sub
    End Class
    

    で、その上で・・・
    とりあえずコードの問題点そのものを指摘したわけですが、質問の内容と併せて見るに、「オブジェクトとインスタンス」「変数のスコープ」といった、ごく基本的な重要事項が理解できていないように見受けられます。
    ここらへん説明し出すと日が暮れる(笑)んで、ご自分で調べて下さいとしか言いようが無いんですが、ちゃんと理解していないと同じような事でずっと躓くことになりかねないので、ちょっと気合い入れて勉強してみて下さい。
    何事も一朝一夕に身につくものではなく、地道な繰り返しが全体の理解へと繋がります。諦めなければいつか必ず理解に至りますから、粘り強く頑張ってください。
    • 回答としてマーク firstlilac 2012年10月20日 8:15
    2012年10月20日 7:05
  • おしえていただいたことに応用をきかせようと、Form4からForm5に行かせてからForm3に戻らせてみました。

    [Form4のコード]

    Public Class Form4
        Public f3 As Form3
        Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f5 As New Form5
            f5.f4 = Me
            f5.Show()
        End Sub
    End Class

    [Form5のコード]

    Public Class Form5
        Public f4 As Form4
        Private Sub Form5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f5 = Me
            f4.f3.f2 = Me.f4.f3.f2
            f3.Show()
        End Sub
    End Class

    これだとやはりエラーが生じます。これでは新しいf3にf2を代入したことにはならないのでしょうか??


    むずかしい・・・
    2012年10月20日 9:20
  • さらに、Form4とForm5の間を3回いったりきたりした後、Form3に戻るということを考えています。

    いろいろ試していますが難しい…


    Public Class Form5
        Public f4 As Form4
        Public Shared a As Integer
        Private Sub Form5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            a = a + 1
        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            If a < 3 Then
                Dim f4 As New Form4
                f4.f5 = Me
                f4.Show()
            ElseIf a = 3 Then
                Dim f3 As New Form3
                f3.f5 = Me
                f4.f5.f4.f5.f4.f3.f2 = Me.f4.f5.f4.f5.f4.f3.f2
                f3.Show()
            End If

          
        End Sub
    End Class

    これでもやはりForm3においてForm2の参照ができないようです・・・

    2012年10月20日 9:37
  • わー!

    信じられない方法でうまくいきました

    なんとなくかぎ括弧でくるんでみたらできました…

    なぜうまくいったのかもよくわかりませんが…

    解決できたのでありがとうございました

    2012年10月20日 11:17
  • なんか難しく考えすぎなような気が・・・

    Form5の

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3・・・①
            f3.f5 = Me
            f4.f3.f2 = Me.f4.f3.f2・・・②
            f3.Show()
        End Sub

    この部分ですが、①で新しくForm3クラスをf3という変数へインスタンスして格納しています。
    今からShowするのはこの新しいf3オブジェクトなので、ここのf2にForm2のインスタンスを代入しなければなりません。
    ところが②はMeが省略されているだけでf4内のf3オブジェクトのf2へ同じモノを代入する事になりますので、これでは意味がありません。
    ②の部分はf3.f2 = Me.f4.f3.f2とするのが正解です。

    Public Class Form5
         Public f4 As Form4
         Private Sub Form5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
     
        End Sub
     
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
             Dim f3 As New Form3
             f3.f5 = Me
             f3.f2 = Me.f4.f3.f2
             f3.Show()
         End Sub
     End Class
    

    2012年10月20日 11:23
  • なんとなくかぎ括弧でくるんでみたらできました…

    なぜうまくいったのかもよくわかりませんが…

    解決できたのでありがとうございました

    解決できたから良しとするのでは、プログラミングは状態しませんよ。一つずつ理解しながら進みましょう。
    これまでの流れから、鍵括弧で解決するようには思えません。せっかくですので、本当に理解できるまで、もう少し頑張ってみませんか?
    ところで、鍵括弧は予約語を変数として使えるようにする書き方です。以下のページの「基礎知識 & キーワード」の「変数名について」をご覧ください。

    3-1 変数と定数
    http://msdn.microsoft.com/ja-jp/library/dd314343.aspx

    なお、VBには既定のインスタンスという、ちょっと混乱しやすい仕組みがありますので、ご注意ください。

    (参考)
     Formを呼び出す場合にNewは絶対に必要なのでしょうか
    http://social.msdn.microsoft.com/Forums/ja-JP/vbgeneralja/thread/55781635-aaee-4f5b-85bb-29f3b4ce7c03/

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年10月20日 13:07
    モデレータ
  • みっとさん trapemiyaさん

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f5 = Me
            f3.f2 = Me.f4.f3.f2
            f3.Show()
        End Sub

    としなくてはならないことにはすぐ気づいたのですが、それでも何故かうまくいかなかったので

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f3 As New Form3
            f3.f5 = Me
            f3.f2 = (Me.f4.f3).f2
            f3.Show()
        End Sub

    としてみたら参照できたのです…

    2012年10月21日 1:03
  • 鍵括弧ではなく、普通の括弧なのですね。ちなみに鍵括弧とは、[]のことです。
    ところで、Me.f4.f3.f2と(Me.f4.f3).f2に違いはありません。メンバーアクセス式は左から順に解決されていきます。別の言い方をすれば、左のあるもの、この場合はf2の左にあるものは修飾子のようなものです。例えば、末広町だけだとどこの末広町かわかりませんので、以下のように末広町の場所をプロパティのように表せば、
    千葉県.柏市.末広町
    東京都.青梅市.末広町
    のようになりますが、
    (千葉県.柏市).末広町
    (東京都.青梅市).末広町
    としても、違いがないようなものです。
    #クラスにはインスタンスという概念がありますので、上の住所のイメージでそのまま捉えないでください。インスタンスは複数作成できますので、東京都、青梅市、末広町などを同時に複数存在させることができると思って下さい。複数存在させることができますので、インスタンスが異なればその中身は別物になります。つまり、2回newして、
    東京都.青梅市.末広町を2つ同時に作成することができますが、それらは全くの別物であることに注意して下さい。

    ですから、うまく行ったのは、どこかほかに原因があると思います。今、うまく行っている状態で、一度このカッコを外してみて下さい。おそらく問題は発生しないはずです。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年10月22日 1:17
    モデレータ