サブフォームからメインフォームを操作し、サブフォームの前に表示させる

タグの編集
投稿者 こじろー  (社会人) 投稿日時 2022/2/21 17:17:31
以下、簡単な例です。
メインフォーム(Form1)と、2つ目のフォーム(Message_Form)は、メインフォームが大きく、二つ目のフォームと重なります。
メインフォームのButton3に

Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim f As New Message_Form
        f.Owner = Me
        f.TopMost = True
        f.Show()
 End Sub
2つ目のフォームのOKButtonに、以下の記述をして、Form1の前に来た2つ目のフォームのMessage_FormがOKボタンを押すと、Form1がその前に来るようにしたいのです。

Public Class Message_Form
    Private Sub OK_Button_Click(sender As Object, e As EventArgs) Handles OK_Button.Click
        Me.TopMost = Not Me.TopMost
        Owner.TopMost = True
    End Sub
End Class

Me.TopMost = Not Me.TopMostはMe.TopMost =Falseでも行いましたが、できません。
無理でしょうか?
投稿者 るきお  (社会人) 投稿日時 2022/2/21 19:05:32
単純にFormの前後関係を変える用途ではOwnerやTopMostは目的も違いますし使いにくいです。
BringToFrontメソッドはフォームを前に表示する機能なのでこれを利用するとよいと思います。

私ならこう書きます。

Form1
Public Class Form1

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim f As New Message_Form
        f.MainForm = Me
        f.Show()
    End Sub
End Class


Message_Form
Public Class Message_Form

    Public Property MainForm As Form1

    Private Sub OK_Button_Click(sender As Object, e As EventArgs) Handles OK_Button.Click
        MainForm.BringToFront()
    End Sub
End Class


ちなみにMessage_Form側と SendToBack する方法もありますが、これだと一番後ろに回されます。
投稿者 こじろー  (社会人) 投稿日時 2022/2/21 20:29:56
簡単な例を、改めて作ってみました。
Imports System.Windows.Forms
Imports Microsoft.Win32
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim f As New Form2
        f.Owner = Me
        'f.TopMost = True
        f.Show()
    End Sub
End Class

mports System.Windows.Forms
Imports Microsoft.Win32

Public Class Form2
    'Public Property MainForm As Form1  <-使いません。
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form1.BringToFront()
        'MainForm.BringToFront()
    End Sub
End Class
で、やってみましたが、だめでした。VS2013です。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2022/2/21 21:18:45
> 簡単な例を、改めて作ってみました。

その例の場合、Form2 の Owner が Form1 になっていますよね。
そのため、Form2 が Form1 よりも手前に来ることはありません。

Owner を指定していなければ、BringToFront で手前に来ます。


たとえば
Form2 の Owner が Form1 で
Form3 の Owner が Form1 の場合、
Form2 を Form3 より手前にしたり、Form3 を Form2 より手前にすることはできます。
しかし Form1 が Form2 や Form3 よりも手前に来ることはできません。
Form1 がそれらのオーナーだからです。
投稿者 こじろー  (社会人) 投稿日時 2022/2/22 09:10:02
Imports System.Windows.Forms
Imports Microsoft.Win32
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim f As New Form2
        f.Owner = Me
        f.TopMost = True
        f.Show()
        Dim f2 As New Form3
        f2.Owner = Me
        'f.TopMost = True
        f2.Show()
    End Sub
End Class

Imports System.Windows.Forms
Imports Microsoft.Win32
Public Class Form2
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form3.BringToFront()
    End Sub
End Class

Imports System.Windows.Forms
Imports Microsoft.Win32
Public Class Form3
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form2.BringToFront()
    End Sub
End Class
で、だめでした。無理なようです。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2022/2/22 12:35:23
BringToFront や SendToBack は、Owner での親子関係や TopMost の最前面表示を
超えて切り替える事はできません。あくまでも、マウス操作で切り替えられる範囲の切り替えだけです。

> で、だめでした。無理なようです。

提示されたコードを見る限り、幾つか不自然な個所があります。

f (Form2) の Owner は Me (Form1)
f2 (Form3) の Owner も Me (Form1) になっているため、
この場合の親子関係はこのようになります。
 Form1
  ┣Form2
  ┗Form3


Form1 は親なので、子である Form2 や Form3 よりも手前に来ることはできません。
Owner を一切指定しないのであれば、Form1 が手前に来ることもできます。

Form2 と Form3 は兄弟なので、本来であればどちらを手前にすることもできるのですが、
今回は Form2 が TopMost ですが、Form3 はそうではないため、
Form2 が常時手前にくることになります。

もしも TopMost を設定したウィンドウが複数あった場合には、
TopMost 同士の中でのみ、前面/背面の切り替えが可能です。

上記の仕様について、認識されていますか?


結果として、Form2 が最前面表示、Form1 が最背面で、その間に Form3 がくる形となります。

もしもそれでは都合が悪いというのであれば、TopMost や Owner の指定を
見直してみてください。BringToFront を用いるのは、その後の話です。



> Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
>   Form3.BringToFront()
> End Sub
Form2/Form3 が表示されている最中に、Form1 の Button1 をもう一度押しててみてください。
押した数だけ、Form2 や Form3 が生成・表示されますよね?

これは、Form1 の Button1 内で
 「Dim f As New Form2」
 「Dim f2 As New Form3」
として、Form3 を毎回 【New】で生成し、それを【Show】しているためです。

たとえば Form3 を生成した後で、
 Dim f2 As New Form3
 f2.Text = Now.ToString("HH:mm:ss.fff")
のように、いつ生成したのかをタイトルに記録しておくと、
複数起動したときに、どちらが先に生成したものかを確認出来るでしょう。


一方、Form2 で操作しているのは、それらとは無関係の
 Form3.BringToFront()
です。

f2 な Form3 インスタンスは Show していましたが、
Form3 な Form3 インスタンスはまだ Show したことが無いので、
これは「まだ表示されていないフォームを手前に表示しようとしている」ことになります。

MsgBox( Form3.Visible ) 'まだ表示されていないので False が表示される 
MsgBox( Form3.Text ) ' Form1 で「生成時刻」をセットしたのとは別インスタンスなので、既定値のまま 
Form3.BringToFront() 'まだ表示されていないフォームなので、手前に表示しようがない 


Form1 で「New」したフォームを操作したいのであれば、複数起動される可能性あるフォームのうち、
どのフォームを手前に表示したいのか、そのインスタンスを明示して BringToFront する必要があります。
たとえば下記のようにすれば、現在開かれている Form3 フォームを、
順次手前に持ってくることになります。(Owner や TopMost の壁は越えられませんが)
For Each f As Form3 In Application.OpenForms.OfType(Of Form3)()
    f.BringToFront()
Next


一方、そういった明示的なインスタンス管理を行わず、暗黙のフォーム変数で操作したいのなら
Form1 の中でも New は使わずに、「Form2.Show(Me)」 で表示させるようにして、統一性を図りましょう。
投稿者 こじろー  (社会人) 投稿日時 2022/2/22 19:31:38
>Form1 の中でも New は使わずに、「Form2.Show(Me)」 で表示させるようにして、統一性を図りましょう

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form2.show(Me)
        Form3.show(Me)
    End Sub
End Class
で、Form2,3のボタンは正常に動きました。
投稿者 こじろー  (社会人) 投稿日時 2022/2/22 19:33:20
るきおさん。魔界さん。どうもありがとうございました。