ListBoxクリック ページ移動

タグの編集
投稿者 スピリタス  (社会人) 投稿日時 2012/6/1 18:55:13
下記の流れの処理を実現したいです。

1.リストボックスに表示されている値を選択してダブルクリックまたはEnterを押下
2.現在のフォームを閉じてリストボックスで選択された値を別フォームのテキストボックスにセットして表示させたいです。

すいませんが簡単なサンプルソースを教えて下さい。
投稿者 zz6989  (社会人) 投稿日時 2012/6/1 20:52:33
こんばんは、質問の内容とは違うかもしれませんが、一応下記のようでいいでしょうか?
Form1側
Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim st As New ArrayList
        st.Add("abc")
        st.Add("def")
        st.Add("ghi")

        ListBox1.Items.AddRange(st.ToArray)
    End Sub

    Private Sub ListBox1_DoubleClick(sender As System.Object, e As System.EventArgs) Handles ListBox1.DoubleClick
        Dim selectst As String
        selectst = ListBox1.SelectedItem

        Dim f As New Form2
        f.Opener = Me
        f.Show()
        f.TextBox1.Text = selectst

    End Sub
End Class

 
 

Form2側
Public Class Form2
    Public Opener As Form
    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim f As Form1
        f = Me.Opener

        f.Visible = False
    End Sub
End Class
 
 
質問の内容と違ってましたらすいません。
今のうちに、謝っておきます。


投稿者 m190  (社会人) 投稿日時 2012/6/2 01:53:53
これまで私、Form 1個にコントロール 2~3個程度のものしか作ったことが無かったので、
勉強しなきゃと、↓のページを参考に、Form間でのデータの受け渡しに挑戦してみました。

http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard29.htm

で、Formの表示と同時にデータも受け渡せたら便利だなと、↑を見よう見まねで、、、
というよりコピペですが・・・(汗)、オーバーロード版つくってみました。
#ページを読みつつ色んなやり方があるんだなぁと、しみじみ思いました。

こんな感じです
Public Class Form1
    Dim LB1 As New ListBox With {.SelectionMode = SelectionMode.MultiSimple}
    Sub Form_Load() Handles Me.Load         'ここは全部リストボックスの準備 
        Me.LB1.Items.AddRange({1, 2, 3, 4, 5})
        Me.Controls.AddRange({LB1})
        AddHandler LB1.DoubleClick, AddressOf test
    End Sub
    Sub test()                          'ここが DoubleClickした時の処理の部分 
        Form2.Show(MeMe.LB1.SelectedItems)    '←オーバーロード版を呼び出し 
        Me.Hide()               ' Form2へ選択項目の情報を渡したら自分は消える 
    End Sub
End Class

Class Form2
    Inherits Form
    Sub test() Handles Me.FormClosing           'もし自分が消えそうになったら 
        Me.Owner.Show()                         '忘れずに呼び出し元を表示する 
    End Sub
    Public Overloads Sub Show(ByVal Owner As IWin32Window, _
                    ByVal ListBox_DATA As ListBox.SelectedObjectCollection)
        'Form1からListBox(LB1)の選択項目↑も受け取る(&その選択項目の型を指定) 
        Dim LB2 As New ListBox      '←Form2へListBox(LB2)を追加(毎回初期化) 
        Me.Controls.Add(LB2)
        For Each i In ListBox_DATA  'ListBox_DATAは Form1.LB1のSelectedItems 
            LB2.Items.Add(i)            'ListBox_DATAの中身を 1個づつ追加する 
        Next
        Me.Show(Owner)                      '後々のために呼び出し元を覚えておく 
    End Sub     '#見た目がショボいのは勘弁してください(人間見た目じゃないよ!) 
End Class

それで、↑では引数で受け取った ListBox_DATAを 1個づつ追加してますが、
これって何とかして、一度にまとめて追加はできないものでしょうか?
#いっぺんに設定できても良さそうなんですが、型の指定が悪いんでしょうか?

どなたかご存知の方、教えてください。  m(_~_)m<よろしくお願いします

投稿者 m190  (社会人) 投稿日時 2012/6/2 02:31:44
すみません事故レスです、以下のように出来ました。
Class Form2
    Inherits Form
    Sub test() Handles Me.FormClosing
        Me.Owner.Show()
    End Sub
    Public Overloads Sub Show(ByVal Owner As IWin32Window, _
                    ByVal ListBox_DATA As ListBox.SelectedObjectCollection)
        Dim LB2 As New ListBox With {.DataSource = ListBox_DATA}
        Me.Controls.Add(LB2)'↑初期化の時に、ついでにデータも設定しちゃう版 
        Me.Show(Owner)
    End Sub
End Class

それでは、おやすみなさい。。。
投稿者 zz6989  (社会人) 投稿日時 2012/6/2 06:09:51
おはよう御座います。
m19さん、いつも有用な情報有難う御座います。とても勉強になりました。
Inherits はこの講座でも勉強しましたが、すっかり忘れてました(入門者らしいでしょう)(汗
それはさておき。アプリケーションの終了を忘れてましたので追記しておきます。
Public Class Form2

    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim f As Form1
        f = Me.Owner
        Button1.Text = "終了します。"  '追加 
        
    End Sub

'追加 
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Form1.Close()
        Me.Close()

    End Sub
End Class
 


あとは、終了しますか?、とか、キャンセルしますか?の指定をしたい時は、この講座の第29回 2つ目のフォーム  5.モーダルフォームあたりを参照してください。ちなみに×をクリックして終了させる方法は今までやったことがないので、必要であればm19さん(この人面白いでしょ)(笑 
又は他の方に聞いてください。


投稿者 zz6989  (社会人) 投稿日時 2012/6/2 11:25:51
たびたび失礼します。
終了の仕方ですけど、ちょっと、いやだいぶ邪道かもしれませんが、メニューバーを、プロパティ画面でFormBorderStyle.Noneにして、適当にダミーのメニューバーをPictureBoxで作って×なしのメニューバーでもいいでしょうか?

画面の大きさ変更は、ダミーのメニューバーにButtonを2個貼り付けて変更できるようにしておく。↓
 Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        ' フォームを最大化する 
        Me.WindowState = FormWindowState.Maximized
    End Sub

    Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
        ' フォームを最小化する 
        Me.WindowState = FormWindowState.Minimized
    End Sub
 

 または、大きさを最大化、最小化だけではなく、元の大きさに指定するとか。
すいません、本題からだいぶそれてしまったことにお詫びします(平伏
投稿者 (削除されました)  () 投稿日時 2012/6/2 13:43:45
(削除されました)
投稿者 るきお  (社会人) 投稿日時 2012/6/2 13:55:35
今回の件ポイントは2つあります。 

1つは、呼び出し元のフォーム(Form1とします。)を閉じてしまうことです。
既定の設定だとForm2を開いた後でもForm1を閉じるとアプリケーションが終了してしまいます。
そこで、m190さんはフォームを閉じる代わりにMe.Hideを使用しており、zz6989さんはVisible = Falseでかわしています。
しかし、これだと今後はForm2を閉じた場合にすべてフォームが表示されていないのにアプリケーションが終わらないことになってしまいます。

2つめはForm1とForm2は互いに疎遠であるべきということです。
Form1を変更した場合にForm2にプログラムも連動して修正したり、逆にForm2を変更したときにForm1を連動して修正したりする必要がある事態はできるだけ避けたいものです。
私は互いに疎遠であることを「疎結合」と呼んでいます。 

以上、2点を踏まえたコード例を紹介します。

前提としてプロジェクトのプロパティ画面でシャットダウンモードを「最後のフォームが閉じるとき」に変更してください。
これによってForm1を閉じてもForm2が開いている限りアプリケーションは終了しなくなります。
 
※この画像は他から流用しているので赤い四角で囲ってある部分は関係ありません。 

Form1側
Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        ListBox1.Items.AddRange({"Apple""Banana""Cat""Dog"})

    End Sub

    Private Sub ListBox1_DoubleClick(sender As Object, e As System.EventArgs) Handles ListBox1.DoubleClick

        If ListBox1.SelectedItem Is Nothing Then
            '何も選択されていなければ何もしない。 
            Return
        End If

        Dim f As New Form2
        f.Show(ListBox1.SelectedItem)
        Me.Close()
    End Sub

    Private Sub ListBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles ListBox1.KeyPress

        If e.KeyChar = Chr(Keys.Enter) Then
            ListBox1_DoubleClick(sender, e)
        End If

    End Sub

End Class


Form2側
Public Class Form2

    Public Overloads Sub Show(value As String)
        Me.TextBox1.Text = value
        Me.Show()
    End Sub

End Class
 
投稿者 zz6989  (社会人) 投稿日時 2012/6/2 14:55:50
るきお先生へ、適切なアドバイス有難う御座います。

投稿した後で、終了に関していい考えが思いつきませんでした、この講座の「2つ目のフォーム」のところでOverloadsの使い方を習っていましたが、今回それと同じことをしても、どうしても上手くいきませんでした。
プロジェクトのプロパティ画面でシャットダウンモードを「最後のフォームが閉じるとき」のことは、ぜんぜん思いつかず、結局誰かに助けてもらおうと思っていました。
今回は、スピリタスさんが質問してくださったおかげで、私も大きな収穫を得てしまいました。

有難う御座いました。
投稿者 m190  (社会人) 投稿日時 2012/6/3 22:13:26
やり方が様々あるというだけでなく、使い方も色々だよ、ってことも言えますね。
たとえば、あくまで Form1がメインで一時的に Form2を表示するのか、それとも Form1は
用済みだから破棄しちゃって Form2に乗り換えたいのか、あるいは Form1が本命なんだけど 
Form2も Form3も Form4も色ーんな Formとお付き合いしたいのか、そのお付き合いの仕方(?)
みたいのを想定すると、逆にどれが適切な手法かが選び易くなる、、、みたいな感じでしょうか。


話は変わりますが、
終了ボタンとForm右上の×ボタンの区別について、最初は、FormClosing イベントのときに渡される 
FormClosingEventArgs クラスの CloseReason プロパティなどで調べれば違いが分かるかと思ったんですが、
(実験の仕方が悪いのかもしれませんけど)どちらの場合も UserClosing だったため見分けることが出来ませんでした。
# Form1側 を閉じたときの FormOwnerClosing ならば区別できました

仕方が無いので、何か簡単そうな方法はないかと考えたんですが、
終了の方法(=Closeの呼び出しかどうか)の情報をクラスレベルで持つことにして、
その情報を見て処理を切り分ける、って感じの流れになるのかな?と思いました。

たとえば
終了ボタンを押したとき、情報に「終了ボタンを押したんだよ!(=Closeの呼び出しだよ!)」
みたいな情報を記憶させた上で Close()メソッドを呼び出す。
#Showが出来るんだから、Closeメッソドをオーバーロードしても良いのかも

そして Formが閉じられる際に必ず通過する FormClosingイベントなどでその情報を読み取って、
もしそれが、×ボタンによる終了だったら(=Closeメソッドの呼び出しではない場合)
Closeをキャンセルする、みたいな感じです。

#ただ、他に方法ありそうな気もするんですが、、、何だかヘルプ読んでても難しくて。。。
一番手軽そうだったのがこの方法でした。
投稿者 スピリタス  (社会人) 投稿日時 2012/6/4 18:12:12
皆様回答ありがとうございます。

一通り読ませて頂きました。
るきお先生のを参考にプログラムを組みました。
ある程度希望通りの動きをする事が出来ました。

私の最初の書き方に不足があり申し訳ないですがフォーム間の動きは下記のようにしたいです。

1.初期表示はFORM1を表示
  ボタンをクリックするとFORM2を表示

2.FORM2のリストボックスをエンターまたはダブルクリックするとその値を
  FORM1のテキストボックスにセットしてFORM2を閉じFORM1のテキストボックスをフォーカス

という流れにしたいです。
私もソースを学び方法を模索中ですがアドバイスあればよろしくお願いします。
投稿者 zz6989  (社会人) 投稿日時 2012/6/5 06:54:45
スピリタス さんへ、先日はご迷惑おかけしました。

>1.初期表示はFORM1を表示、ボタンをクリックするとFORM2を表示

>2.FORM2のリストボックスをエンターまたはダブルクリックするとその値をFORM1のテキストボックスにセットしてFORM2を閉じFORM1のテキストボックスをフォーカス

以上のケースと、るきお先生の書いてくださったコードを崩さずにサンプルを書いてみました。
但し、問題は、るきを先生のご意見「プロジェクトのプロパティ画面でシャットダウンモードを「最後のフォームが閉じるとき」に変更してください。」は初期状態のままですが、これですとスピリタス さんの目的は果たされないんですよね?

Form1側
Public Class Form1
    Public Overloads Sub Show(value As String)
        TextBox1.Text = value
        Me.Show()
        TextBox1.Focus()  '追加した部分です。 

    End Sub
    'ボタンをクリックしたときにForm2を表示します。  追加した部分です。 
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim f As New Form2
        f.Owner = Me
        f.Show()
    End Sub

End Class
 


Form2側
Public Class Form2

    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ListBox1.Items.AddRange({"Apple""Banana""Cat""Dog"})

    End Sub
    Private Sub ListBox1_DoubleClick(sender As Object, e As System.EventArgs) Handles ListBox1.DoubleClick

        If ListBox1.SelectedItem Is Nothing Then
            '何も選択されていなければ何もしない。  
            Return
        End If

        '追加した部分です 
        Dim selectst As String
        selectst = ListBox1.SelectedItem
        Dim f As New Form1
        f = Me.Owner
        f.Show(selectst)

        Me.Close()
    End Sub
    Private Sub ListBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles ListBox1.KeyPress

        If e.KeyChar = Chr(Keys.Enter) Then
            ListBox1_DoubleClick(sender, e)
            
        End If
        
        Me.Close()

    End Sub

End Class

投稿者 zz6989  (社会人) 投稿日時 2012/6/5 12:45:25
追記と訂正です。

>プロジェクトのプロパティ画面      初期状態のままですが
シャットダウンモードが「スタートアップフォームが閉じるとき」のことです。
るきお先生が書いてくださったコードの動作が目的の動作であれば、また的外れのサンプルかもしれません、的外れだったらごめんなさい。

Form2側
 
 Public Class Form2
    Private Sub Form2_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        ListBox1.Items.AddRange({"Apple""Banana""Cat""Dog"})

    End Sub
    Private Sub ListBox1_DoubleClick(ByVal sender As ObjectByVal e As System.EventArgs) Handles ListBox1.DoubleClick

        If ListBox1.SelectedItem Is Nothing Then
            '何も選択されていなければ何もしない。   
            Return
        End If

        '追加した部分です  
        Dim f As New Form1
        f = Me.Owner
        f.Show(ListBox1.SelectedItem)  '変更した部分です。 
        Me.Close()
    End Sub
    Private Sub ListBox1_KeyPress(ByVal sender As ObjectByVal e As System.Windows.Forms.KeyPressEventArgs) Handles ListBox1.KeyPress

        If e.KeyChar = Chr(Keys.Enter) Then
            ListBox1_DoubleClick(sender, e)

        End If

        Me.Close()

    End Sub

End Class


せっかくOverloadを使用していますので、後でListBoxの値をInteger型などに変更した場合、るきお先生のコードのように f.Show(ListBox1.SelectedItem) としておくと、有利だと思います。
 Public Overloads Sub Show(ByVal value As Integer)みたいに同じShowでも、型が違うメソッドを複数利用できますしね。

投稿者 shu  (社会人) 投稿日時 2012/6/5 12:58:16
Form2のインタフェースが違いますが例えばこんな感じ。

Form1
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Form2.Show()
        AddHandler Form2.FormClosing, AddressOf Form2_FormClosing
        Me.Hide()
    End Sub

    Private Sub Form2_FormClosing(sender As Object, e As FormClosingEventArgs)
        If Form2.Result IsNot Nothing Then
            TextBox1.Text = Form2.Result
        End If
        Me.Show()
    End Sub



Form2
    Private _result As String = Nothing
    Public Property Result As String
        Get
            Return _result
        End Get
        Set(value As String)
            _result = value
        End Set
    End Property

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        _result = TextBox1.Text
        Me.Close()
    End Sub
投稿者 スピリタス  (社会人) 投稿日時 2012/6/5 14:26:19
皆様回答ありがとうございます。

 zz6989さんがるきお先生のソースを崩さず修正して頂いたおかげで目的の動きをする事が出来ました。
質問内容に対して予想以上に話が広がったのでとても勉強になりました。

回答ありがとうございました。
まわよろしくお願いします。
投稿者 m190  (社会人) 投稿日時 2012/6/5 22:13:22
> 質問内容に対して予想以上に話が広がったのでとても勉強になりました。
私もおかげ様で、とっても勉強になりました。

るきお先生の、プロジェクトのプロパティ(シャットダウンモード)もそうですが、
shu さんのサンプルコート、Form2 のイベントで Form1 のプロシージャを
駆動させちゃうなんて、「へぇーボタン」連打しまくりでした。

もし私一人だったらこんなアイデアとても思いつきません。なるほど、そういう使い方も
出来るんだよなぁ、、、と感心しまくりでしたが、同時に、これをきちんと使いこなすには、
(何事もそうですけれど)やっぱり基礎をしっかり固めないと大怪我の基だな、とも思いました。

#またまた勉強することが増えちゃいました、宿題山積みです(困