C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 同一フォームをアプリケーション内で使いまわす


(過去ログ 111 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■65917 / inTopicNo.1)  同一フォームをアプリケーション内で使いまわす
  
□投稿者/ LOC (19回)-(2013/03/22(Fri) 20:06:16)

分類:[VB.NET/VB2005 以降] 

お世話になっております。LOCと申します。

あるフォームをアプリケーション内で使いまわしたいと考えています。

・FormA ⇒ メイン画面 
・FormB ⇒ サブ画面
・FormC ⇒ 使いまわしたいフォーム


動きとしては、以下の動作をさせたいと考えております。

 ・FormAを起動
 ・FormAからFormCを起動(モードレス)
 ・FormAからFormBを起動(モーダル)
 ・FormBから起動しているFormC前面に表示(モードレス)
 

実際にコーディングしたのは、下のような感じです。 
==============================================================
            Dim c As FormC = Nothing

            For Each f As Form In My.Application.OpenForms
                If (f.GetType() Is GetType(FormC)) Then
                    c = DirectCast(f, FormC)
                    Exit For
                End If
            Next

            If (c Is Nothing) Then
                c = New FormC()
            End If

            c.Show()
            c.BringToFront()
==============================================================

実行してみたところ、最前面にも来ず、FormBの後ろで処理済みのフォームが
存在しているだけでした。
※FormBをモードレスにすると最前面に出てきてくれるのですが。。
アプリケーションの仕様上、FormBはモーダルではなくてはなりません。



試しに c.Show() に呼び出す OwnerForm を設定してみたのですが、
最前面には来るのですが、画面を触ることができませんでした。
(ボタンクリック、フォームを移動するなど)


別フォームで同じオブジェクトのフォームを使いまわすことは可能でしょうか。



引用返信 編集キー/
■65918 / inTopicNo.2)  Re[1]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ まつかさ (1回)-(2013/03/22(Fri) 20:25:30)
FormBはどのようにしてモーダルにしていますか?
FormBがモーダルである必要があるのはFormAに対してのみならば、

Dim f As New FormB
f.ShowDialog(Me) 'MeがFormAのインスタンスを指していることを前提

で行えばいいのではないでしょうか。

#実際に各フォームをどのように開いているか分からないので何とも言えません。
 あと、以下のコードはFormAのものでしょうか?
 もしそうならば、なぜ以下のようにFormCをわざわざMy.Application.OpenFormsから探すのかが良く分かりません。
 FormA内にPrivateな変数を用意し、そこに格納すればいいと思うのですが。

> ==============================================================
> Dim c As FormC = Nothing
>
> For Each f As Form In My.Application.OpenForms
> If (f.GetType() Is GetType(FormC)) Then
> c = DirectCast(f, FormC)
> Exit For
> End If
> Next
>
> If (c Is Nothing) Then
> c = New FormC()
> End If
>
> c.Show()
> c.BringToFront()
> ==============================================================

引用返信 編集キー/
■65921 / inTopicNo.3)  Re[2]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ LOC (20回)-(2013/03/23(Sat) 14:42:25)
No65918 (まつかさ さん) に返信

返信ありがとうございます。

> FormBはどのようにしてモーダルにしていますか?
> FormBがモーダルである必要があるのはFormAに対してのみならば、
> 
> Dim f As New FormB
> f.ShowDialog(Me)    'MeがFormAのインスタンスを指していることを前提
> 
> で行えばいいのではないでしょうか。

ご指摘の通り、FormB は FormA でインスタンス生成し、
ShowDialog() メソッドで画面を表示させています。

 
> #実際に各フォームをどのように開いているか分からないので何とも言えません。
>  あと、以下のコードはFormAのものでしょうか?
>  もしそうならば、なぜ以下のようにFormCをわざわざMy.Application.OpenFormsから探すのかが良く分かりません。
>  FormA内にPrivateな変数を用意し、そこに格納すればいいと思うのですが。
> 
>>==============================================================
>>            Dim c As FormC = Nothing
>>
>>            For Each f As Form In My.Application.OpenForms
>>                If (f.GetType() Is GetType(FormC)) Then
>>                    c = DirectCast(f, FormC)
>>                    Exit For
>>                End If
>>            Next
>>
>>            If (c Is Nothing) Then
>>                c = New FormC()
>>            End If
>>
>>            c.Show()
>>            c.BringToFront()
>>==============================================================
> 

上記のコードは共通関数を定義しているクラスに用意しています。
FormC は FormA または FormB からも呼ばれるためです。

FormA、FormB で使用する FormC は同じインスタンスのものを使いたいのです。


試しに、FormA に FormB の Private 変数を用意し、FormB をモードレス(OwnerForm指定あり)にしてみたところ、
FormCは最前面に表示され、問題なく動作(初期の問題であったフォームが触れない等)できました。

・FormB をモードレス(OwnerForm指定)
==============================================================
        Private _FormB As FormB = Nothing

        Private Sub OpenFormB()
            If (_FormB Is Nothing) Then
                _FormB = New FormB()
                _FormB.Show(Me)
            End If

            _FormB.WindowState = FormWindowState.Normal
            _FormB.BringToFront()
        End Sub
    End Class
==============================================================

しかし、今度は FormB がモードレス(OwnerForm指定あり)のために、FormA が触れてしまいます。

FormA で起動した モードレスのFormC は モーダルのFormB で OwnerForm を切り替えても
FormA のものとなるのでしょうか。

引用返信 編集キー/
■65922 / inTopicNo.4)  Re[3]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ shu (244回)-(2013/03/23(Sat) 17:03:00)
No65921 (LOC さん) に返信

こんな感じでフォーム間を移るときHideにすればOwner切り替えが出来ます。

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        If ShareForm3 Is Nothing Then
            ShareForm3 = New Form3
        End If
        ShareForm3.Owner = Me
        ShareForm3.Show()
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim frm2 As New Form2
        If ShareForm3 IsNot Nothing Then
            ShareForm3.Hide()
        End If
        frm2.ShowDialog()
    End Sub
End Class

Public Class Form2

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        If ShareForm3 Is Nothing Then
            ShareForm3 = New Form3
        End If
        ShareForm3.Owner = Me
        ShareForm3.Show()
    End Sub

    Private Sub Form2_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        If ShareForm3 IsNot Nothing Then
            ShareForm3.Hide()
        End If
    End Sub
End Class

Module Module1
    Public ShareForm3 As Form3 = Nothing
End Module

引用返信 編集キー/
■65930 / inTopicNo.5)  Re[4]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ LOC (21回)-(2013/03/25(Mon) 11:11:14)
No65922 (shu さん) に返信

shu さん、返信ありがとうございます。


教えていただいたコードでフォームのOwnerを切り替えることができました。
しかし、OwnerFormを切り替えているにも関わらず、最前面に出てきたフォームは
操作不可能なフォームになってしまいます。

・FormA から FormC 起動(モードレス) ⇒ OK

・FormCを起動させたまま

・FormA から FormB 起動(モーダル)  ⇒ OK

・FormB から FormC 起動(モードレス) ⇒ NG
 ↓
 最前面には出てくるが、ボタンが触れない状態です。


DebugではOwnerFormが FormA から FormB へ変わっているのを確認しました。
引用返信 編集キー/
■65931 / inTopicNo.6)  Re[5]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ shu (245回)-(2013/03/25(Mon) 11:51:23)
2013/03/25(Mon) 12:24:44 編集(投稿者)
No65930 (LOC さん) に返信
> ・FormCを起動させたまま
表示させたままという事でしょうか?
それは出来ないです。

No65922に対し以下を追加でForm2表示時にForm3をHide,Showを行います。
ShowするタイミングでForm2が表示済である必要があります。
    Private Sub Form2_Shown(sender As Object, e As System.EventArgs) Handles Me.Shown
        If ShareForm3 IsNot Nothing Then
            ShareForm3.Owner = Me
            ShareForm3.Show()
        End If
    End Sub

Form1の
> Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
> 〜
>        frm2.ShowDialog()
この後にも
If ShareForm3 IsNot Nothing Then
    ShareForm3.Show
End If
を追加すれば多分希望に近い動きになるかと思います。

引用返信 編集キー/
■65932 / inTopicNo.7)  Re[5]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ howling (260回)-(2013/03/25(Mon) 11:51:41)
No65930 (LOC さん) に返信
むむむ?

私の方では特に問題無く触れました。
1つ気になる点として、Form2(FormB)を閉じた際、Form3(FormC)も一緒に閉じてしまうところだけ、
もしかするとLOCさんがしたい挙動と違うのかな?と思いました。

ちなみに、個人的にはForm3(FormC)はそれぞれ別個に作り、ShowDialogすれば良いかと思っています。
それぞれ閉じる時に、「閉じた時の状態」を全て親フォームクラス(FormAとFormB)が覚えておけば良いのかなと。
で、FormBが閉じる時と、FormAがFormBを作成する時に、その情報をお互いに共有してやれば、別にうまく行く気はしています。

でも、今回shuさんがご提示してくださった形式でうまくいきそうですし、大丈夫ですかね。

…問題無く動作したコードを一応書いておきますね。
Form1,2,3はそれぞれ、「Windowsフォーム」で追加しました。


'---------------------------------------------------------------------------------------------------Form1.vb

Public Class Form1
Inherits Form


Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
If Module1.ShareForm3 Is Nothing Then
Module1.ShareForm3 = New Form3
End If

Module1.ShareForm3.Owner = Me
Module1.ShareForm3.Show()
End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim frm2 As New Form2
If Module1.ShareForm3 IsNot Nothing Then
Module1.ShareForm3.Hide()
End If
frm2.ShowDialog()
End Sub
End Class


'---------------------------------------------------------------------------------------------------Form2.vb

Public Class Form2
Inherits Form

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
If Module1.ShareForm3 Is Nothing Then
Module1.ShareForm3 = New Form3
End If
Module1.ShareForm3.Owner = Me
Module1.ShareForm3.Show()
End Sub

Private Sub Form2_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
If Module1.ShareForm3 IsNot Nothing Then
Module1.ShareForm3.Hide()
End If
End Sub
End Class


'---------------------------------------------------------------------------------------------------Form3.vb

Public Class Form3

Private TestInt As Integer

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Button1.Text = "Test" + TestInt.ToString()
TestInt = TestInt + 1
End Sub
End Class



'---------------------------------------------------------------------------------------------------Module1.vb

Module Module1
Public ShareForm3 As Form3 = Nothing
End Module
引用返信 編集キー/
■65934 / inTopicNo.8)  Re[6]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ LOC (22回)-(2013/03/25(Mon) 13:47:50)
返信遅くなりまして申し訳ありません。


No65931 (shu さん) に返信
> ・FormCを起動させたまま
表示させたままという事でしょうか?
それは出来ないです。


申し訳ありません。言葉足らずでした。
表示させたままではなく、オブジェクトとしては存在しているという意味です。
My.Application.OpenFormsで取得できるという意味だったのですが、伝わりますでしょうか?


No65932 (howling さん) に返信

返信ありがとうございます。

> 1つ気になる点として、Form2(FormB)を閉じた際、Form3(FormC)も一緒に閉じてしまうところだけ、
> もしかするとLOCさんがしたい挙動と違うのかな?と思いました。

そうですね。Form2(FormB)と一緒に閉じてしまうのが自分が思っている挙動とは違うところでした。


> ちなみに、個人的にはForm3(FormC)はそれぞれ別個に作り、ShowDialogすれば良いかと思っています。
> それぞれ閉じる時に、「閉じた時の状態」を全て親フォームクラス(FormAとFormB)が覚えておけば良いのかなと。
> で、FormBが閉じる時と、FormAがFormBを作成する時に、その情報をお互いに共有してやれば、別にうまく行く気はしています。

やはり別個にForm3(FormC)のインスタンスを持ったほうがよいのでしょうか。。

Form3(FormC)はForm2(FormB)、Form1(FormA)で表示させるとき、最前面には表示するのですが、
起動画面は編集可能にしたいと考えています。

Form3(FormC)はヘルプ画面のようなイメージです。


コードをもう一度見直してみたところ、Form3(FormC)は最前面に表示され、ボタンも触れるようになりました。
しかし今度は別の問題が発生してしまいました。

Form3(FormC)をヘルプ画面のように扱うため、Form3(FormC)を表示するときにパラメータを渡すようなコードを書いているのですが、
パラメータが変更されたら表示するヘルプを変更する処理が走らなくなってしまいました。


別個にForm3(FormC)を持つように処理を変更したいと思います。
引用返信 編集キー/
■65936 / inTopicNo.9)  Re[7]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ howling (262回)-(2013/03/25(Mon) 15:03:30)
No65934 (LOC さん) に返信
> そうですね。Form2(FormB)と一緒に閉じてしまうのが自分が思っている挙動とは違うところでした。
やっぱりこれはそうでしたかー…。
多分Ownerを変えてから閉じてやれば問題なく行けそうな気がするのですが。

> やはり別個にForm3(FormC)のインスタンスを持ったほうがよいのでしょうか。。

これ自体はどっちでも行けそうな気はします。というか、ここまで実際できてますし。
Moduleを使うことで受け渡しを行っていますが、
実際にはForm1(FormA)がForm2(FormB)に受け渡すだけでいいかと。

> Form3(FormC)をヘルプ画面のように扱うため、Form3(FormC)を表示するときにパラメータを渡すようなコードを書いているのですが、
> パラメータが変更されたら表示するヘルプを変更する処理が走らなくなってしまいました。

これは、shuさんのサンプルの結果そうなってしまったわけではないと思うのですが…。
Form2(FormB)から何かしらの値を渡してやった後に、更新処理が行われていないのでは???
先のコードで、ボタンの値が増加すること自体は確認していますから、おそらくできると思いますよ。

> 別個にForm3(FormC)を持つように処理を変更したいと思います。

それでも良いです。
なんでこの方法を提案したかと言えば、悩まずに済むから、という1点のみです。
Form3(FormC)がどこでどのような状態なのか、というのを考えなくて済みますからね。
ただ、同じインスタンスを使いまわしてvisibleのみを変更するだけの方が、多分処理は軽いですし、
処理速度のことを考慮するようなアプリであれば、オススメしません。
引用返信 編集キー/
■65938 / inTopicNo.10)  Re[8]: 同一フォームをアプリケーション内で使いまわす
□投稿者/ LOC (23回)-(2013/03/25(Mon) 17:13:42)
2013/03/25(Mon) 17:14:44 編集(投稿者)
2013/03/25(Mon) 17:14:10 編集(投稿者)
2013/03/25(Mon) 17:14:04 編集(投稿者)

<pre><pre>■No65936 (howling さん) に返信

>>Form3(FormC)をヘルプ画面のように扱うため、Form3(FormC)を表示するときにパラメータを渡すようなコードを書いているのですが、
>>パラメータが変更されたら表示するヘルプを変更する処理が走らなくなってしまいました。
> 
> これは、shuさんのサンプルの結果そうなってしまったわけではないと思うのですが…。
> Form2(FormB)から何かしらの値を渡してやった後に、更新処理が行われていないのでは???
> 先のコードで、ボタンの値が増加すること自体は確認していますから、おそらくできると思いますよ。


コードを見直してみたところ、自分のコーディングミスでした。申し訳ありませんでした。


> それでも良いです。
> なんでこの方法を提案したかと言えば、悩まずに済むから、という1点のみです。
> Form3(FormC)がどこでどのような状態なのか、というのを考えなくて済みますからね。
> ただ、同じインスタンスを使いまわしてvisibleのみを変更するだけの方が、多分処理は軽いですし、
> 処理速度のことを考慮するようなアプリであれば、オススメしません。

howling さんのお言葉でせっかくここまでできたんだからもうちょっとやってみようと思い、
少し悩みましたが、ようやく意図した挙動にすることができました。


教えていただいたのと少し違うと思いますが、下のような感じにコーディングしたところ、
意図した挙動になりましたので、解決とさせていただきます。
------------------------------------------------------------------------------------------
Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        If (Class1.ShareForm Is Nothing) Then
            Class1.ShareForm = New Form3()
        End If

        Class1.ShareForm.IsOpened = True
        Class1.ShareForm.Owner = Me
        Class1.ShareForm.Show()
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        If (Class1.ShareForm IsNot Nothing) Then
            Class1.ShareForm.Hide()
        End If

        Dim f2 As New Form2()
        f2.ShowDialog()

        If (Class1.ShareForm IsNot Nothing AndAlso Class1.ShareForm.IsOpened) Then
            Class1.ShareForm.Hide()
            Class1.ShareForm.Owner = Me
            Class1.ShareForm.Show()
        End If
    End Sub
End Class

------------------------------------------------------------------------------------------
Public Class Form2

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        If (Class1.ShareForm Is Nothing) Then
            Class1.ShareForm = New Form3()
        End If

        Class1.ShareForm.IsOpened = True
        Class1.ShareForm.Owner = Me
        Class1.ShareForm.Show()
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Me.Close()
    End Sub

    Private Sub Form2_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        If (Class1.ShareForm IsNot Nothing AndAlso Class1.ShareForm.IsOpened()) Then
            Class1.ShareForm.Hide()
            Class1.ShareForm.Owner = Me
            Class1.ShareForm.Show()
        End If
    End Sub
End Class
------------------------------------------------------------------------------------------
Public Class Form3

    Private _Counter As Integer

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        _Counter += 1
        Label1.Text = String.Format("TEST: {0} 回", _Counter)
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Me.Close()
    End Sub

    Private Sub Form3_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Class1.ShareForm = Nothing
    End Sub

    Private _IsOpened As Boolean
    Public Property IsOpened() As Boolean
        Get
            Return _IsOpened
        End Get
        Set(ByVal value As Boolean)
            _IsOpened = value
        End Set
    End Property
End Class
------------------------------------------------------------------------------------------
Public Class Class1
    Public Shared ShareForm As Form3 = Nothing
End Class
------------------------------------------------------------------------------------------

howling さん、shu さん、
とても丁寧にご説明いただきありがとうございました。</pre></pre>

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -