Visual Basic 初級講座
VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

 

Visual Basic 中学校 > 初級講座 >

第29回 2つ目のフォーム

いよいよフォームを1つしか使わないプログラムから脱出です。複数のフォームをうまく制御して高度なアプリケーションを作りましょう。今回はその第一歩です。

この回の要約

・Form2を表示させるには次のようにする。

Dim f As New Form2
f.Owner = Me
f.Show

・ShowDialogメソッドでForm2を表示すると、Form2が閉じるまでForm1を操作できない。

・ShowDialogメソッドの戻り値はForm2のDialoResultプロパティの値。

・呼び出し時にOwnerプロパティをセットしておけば、Form2側ではOwnerプロパティを使ってForm1にアクセスすることができる。

VB2005 対応Application.OpenFormsプロパティを使うとすべての開いているフォームにアクセスできる。

・OwnedFormsプロパティを使うとすべての子フォームにアクセスできる。

2007/01/27改訂:改定前のバージョンはこちら (ただし一部画像は改変されているか失われています)

 

1.フォームの追加

 

今まで入門講座・初級講座等ではフォームを1つだけ使うプログラムを説明してきました。市販の本や、多くのWebサイトでもほとんどの場合フォームを1つしか使わない例が紹介されています。

これは説明を簡単にするための当然の措置なのですが、実際のアプリケーションの多くは2つ以上の画面からできていますからフォームだけので完成するプログラムというのはそれほど多くありません。

今回はまさにこの複数のフォームの使い方を中心に説明します。

さて、フォームを追加するだけなら実はとても簡単です。VBでプロジェクトを作成する際に「Windows アプリケーション」を選択すれば、はじめからフォームが1つある空のプログラムが作成されます。このとき、ソリューションエクスプローラは次のようになっています。この例ではプロジェクト名を「FormTest」 にしています。

VB2005 対応

VB.NET 2003 対応

■画像1:ソリューションエクスプローラ(VB2005) ■画像2:ソリューションエクスプローラ(VB.NET2003)

ソリューションエクスプローラが表示されていない場合は[表示]メニューから[ソリューションエクスプローラ]を選択することで表示させることができます。通常は画面の右上の方に表示されています。

標準的な設定のソリューションエクスプローラでは、現在プロジェクトにどのようなファイルが含まれているかが表示されています。VB2005の場合は初期状態では代表的な項目だけが表示されています。今回のテーマである「フォーム」に関してはすぐわかるようにForm1.vbが本体です。

ここで、もう1つフォームを追加してみます。

FormTestプロジェクトの上で右クリックして、[追加] - [Windows フォームの追加]をクリックします。

■画像3:新しいフォームを追加する

そうすると新しい項目の追加画面が表示されるので新しいフォームの名前を入力して[開く]をクリックします。ここではデフォルトのまま「Form2.vb」という名前を付けることにします。

■画像4:新しい項目の追加ダイアログ

そうすると、次の画像のようにプロジェクトに追加されたForm2.vbがソリューションエクスプローラに表示されます。

■画像5:Form2が追加されたソリューションエクスプローラ

このようにフォームを追加するのは実に簡単です。この調子でいくつもフォームを追加していくことができます。

 

2.フォームのデザイン

 

では、Form1とForm2をデザインして簡単なサンプルアプリケーションを作ってみましょう。

まず、ソリューションエクスプローラでForm1を選択して、Form1のデザイナを表示させてください。

■画像6

デザイナを表示させるには、上の画像の右側のボタンをクリックするかソリューションエクスプローラ上でForm1をダブルクリックします。

念のために言葉の説明をしておきますが、フォームのデザイナとは普段からボタンとかテキストボックスをフォームにぺたぺた貼り付けていくあのおなじみの画面のことです。フォームが1つであればデザイナを特に区別する必要がないのですが、今回はフォームが2つなのでデザイナに注意してください。Form1をデザインしているつもりが、よく見たらForm2だったということがないようにしなければなりません。

さて、デザイナが開いたらForm1にラベルとボタンを1つずつ貼り付けてください。ボタンが押されたらForm2を呼び出すようにします。

ボタンのクリックイベントに次の通り書き込んでください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.Owner = Me
f.Show()

■リスト1:Form2を表示させる

VB2005以降であればShowメソッド(読み方:Show = ショウ)の引数としてOwnerを指定することも可能です。

VB2005 対応

Dim f As New Form2

f.Show(Me)

■リスト2:Form2を表示させる。Showメソッドの引数でOwnerを指定する例。

 

メモ  -  VB2005では

VB2005では以下のように書くことも可能です。しかしVBのおけるオブジェクト指向の学習上好ましくないと思いますし、リスト1の場合とは動作が少し違います。ですので私は以下のような書き方はお勧めしません。ただし、学習上の理由でお勧めしないだけで、機能に欠陥や難点があるということではありません。

VB2005 対応

Form2.Owner = Me
Form2.Show()

■リスト3:Form2を表示させる。VB2005の場合のお勧めしない書き方。

この状態でとりあえず実行してみるとボタンをクリックすると確かにForm2が表示されるのがわかります。

しかもリスト1のようにした場合はボタンを何回もクリックするとForm2がたくさん表示されます。これは1つの金型からたくさんのタイヤキができるように、1つのForm2という型からたくさんのForm2のインスタンスが作成されるからです。このプログラムでインスタンスを作成するためのNewキーワードを使用されている点を思い出してください。実際にフォームを表示させているのはShowメソッドです。

次にForm2の側もデザインします。ソリューションエクスプローラでForm2を選択して、Form2のデザイナを表示させてください。ここにはボタンを1つだけ配置してそのClickイベントに次の通りプログラムしてください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As Form1

f = Me.Owner
f.Label1.BackColor = Color.Red

■リスト4:Form2からForm1に命令する

このプログラムを実行するとForm1のラベルの色が赤くなります。

Form2の側ではOwnerプロパティ(読み方:Owner = オーナー)を見るとForm1が取得できるようになっています。これはForm2のインスタンスを作成するときに、Form2のOwnerプロパティにForm1をセットしているからです。

この場合Me.OwnerとはForm1のことなのですから、この例は次のように書き換えることができそうにも思えますが、この例はエラーになります。

'この例はエラーになります。
Me
.Owner.Label1.BackColor = Color.Red

■リスト5

これはOwnerプロパティがForm型であるのでLabel1というプロパティをVBが発見できないためです。Form1には確かにLabel1を配置していたとしても「OwnerがForm1のことなんですよ」という情報をVBに伝えてあげないと実行できません。

このことはプログラム入力中のインテリセンスを見てもわかります。Me.Owner.Label1と入力しようとしてもインテリセンスの一覧にはLabel1は表示されません。

■画像7

VBにとってはOwnerは単なるFormなのですから無理もありません。

このような事情なのでリスト4のようにForm1型の変数fに一度Ownerをセットしてからfに対して命令するのが良い方法となります。この場合ですとfがForm1型であることはDimで宣言していますからVBにも明らかです。つまりVBには「fがForm1のことなんですよ」という情報が伝わります。

しかし、型変換関数を使って1行で書く方法もあります。DirectCast(読み方:DirectCast = ダイレクトキャスト)は型を明示的に指定する機能があります。次の例は正常に動作します。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応


DirectCast
(Me.Owner, Form1).Label1.BackColor = Color.Red
 

■リスト6:Form2からForm1のLabel1の背景色を変更する

DirectCastを使用すると入力中にちゃんとインテリセンスの中にLabel1が表示されます。「OwnerがForm1のことなんですよ」という情報がちゃんとVBに伝わっている証拠です。

■画像8

なお、DirectCastが使える場面では常にCTypeも使用可能です。上記の例はDirectCastCTypeに置き換えても動作します。しかしながらDirectCastの方が性能が良いです。

 

3.フォームの連携

 

ところで、Ownerプロパティにはもう1つ重要な機能があります。Ownerプロパティが設定されている場合Form2はForm1と運命をともに するのです。たとえば、Form1が閉じられればForm2も閉じられますし、Form1が最小化されればForm2も最小化されます。この連動している状態が気に入らなければOwnerプロパティに何も設定しないでおくことになります。しかし、そうした場合はOwnerプロパティを使用して呼び出しもとのフォームを取得することができませんので2つのフォームを連携させるために別の仕組みが必要になります。

2つのフォームがそれぞれ無関係に動作するのであればフォームの連携について何も注意すべきことはありませんが、たいていの場合は何らかの形で2つのフォームを連携させて動作させることになります。

たとえば、Form2が設定画面であれば、そこで設定した内容をForm1に伝える必要がありますし、Form2がファイルを表示する画面であれば、Form1はどのファイルをどのように表示するのかForm2に伝えなければなりません。このようなケースは無数にあります。

2つのフォームを連携させるにはまず、お互いがお互いの存在を知っていなければなりません。

たとえば、Form1側で次のようにForm2を表示させた場合どうなるでしょうか?

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.Show()

■リスト7:Form1に書く。Form2を表示させる。

この場合Form2は確かに表示されますが、Form2の側ではいったい自分がどこから表示されたのかわかりません。Form1の側では変数fを通じてForm2にアクセスすることができますが、変数fが適用範囲から離れたとたんにForm2にアクセスする通常の手段はなくなります。

そこで、最初に説明したようにOwnerプロパティを使うことになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.Owner = Me
f.Show()

■リスト8:Form1に書く。Form2を表示させる。

Ownerプロパティをこのようにセットしておけば、Form2の側では自分のOwnerプロパティを使って呼び出しもとのフォーム、つまりForm1にアクセスすることができますし、Form1の側でも変数fが適用範囲から離れてもOwnedFormsプロパティ(読み方:OwnedForms = オウンドフォームス)を使って、Form1が所有しているすべてのフォームにアクセスすることができます。OwnedFormsプロパティはFormの配列です。

ただし、Ownerプロパティを設定すると先ほど説明したように2つのフォームは自動的に連動するようになります。これが困る場合は独自の仕組みでフォームを連携させることになります。次にその例を紹介します。

Form2の宣言部に次の1行を追加してください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応


Public
Opener As Form
 

■リスト9:Form2に書く

念のためにこの1行をどこに追加するのかForm2のプログラムの全体を掲げておきます。ここでは、VB2005の例を挙げますが、VB.NET2002、VB.NET2003の場合も「Windows フォーム デザイナで生成されたコード」という部分とInherits...という1行が追加されているだけで他は同じです。

VB2005 対応

Public Class Form2

    Public Opener As Form

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim f As Form1

        f = Me.Opener
        f.Label1.BackColor = Color.Red

    End Sub

End Class

■リスト10:Form2の全体

変数を宣言したらForm1の側でForm2を呼び出す部分を次のように変更することで、Form2の側では変数Openerを使ってForm1にアクセスすることができるようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.Opener = Me
f.Show()

■リスト11:Form1に書く。Form1を表示する。

ただし、こうするとForm1の側からはForm2にアクセスする手段は変数fだけとなってしまいますので、変数fが適用範囲から離れないようにするなど対策を講じる必要があります。Ownerにセットした場合は対象のフォームがOwnedFormsプロパティに自動的に追加されますが、Openerは自作の変数であるためこのような機能がないからです。

また、変数OpenerDimではなくPublic(読み方:Public = パブリック)で宣言されている点にも注意してください。Publicで宣言された変数はこの例のように他のフォームや他のクラスからも参照することができます。もし、Dimで宣言していたならば他のフォームからは参照することができないのでこの変数を使ってフォームを連携させることはできません。

2つのフォームがお互いにアクセスできるようになっていれば基本的な連携はそう難しくありません。前の例で書いたようにForm2のボタンをクリックしてForm1のラベルの色を変えることもできますし、お互いのプロパティやメソッド・変数を呼び出すこともできます。

 

4.パラメータを送る

 

フォームを開いた後でOwnerプロパティやOwnedFormsプロパティ、または先ほど例として示したOpenerなどの変数を使用して連携することはここまでの説明で可能になっています。

この他によくあるフォーム同士の連携としてはフォームを開くときに何かのパラメータを送りたいという要求です。メソッドを作る説明をしたときに私は呼び出しが正しければ常に正しい結果が得られるようにメソッドを設計すべきであって、外部の変数などに頼ってはいけないということを書きました。そうしなければプログラム中で制御しなければいけない項目が飛躍的に増大してプログラムが複雑になればなるほど収拾できなくなってしまうからです。

フォーム同士の連携を行う場合でも基本的にはこのスタンスがあてはまります。フォームを開くときに情報を送り込む方が、フォームを開いた後で情報を受け渡しするより整理された良いプログラムとなるケースが多いです。

このことを実現するためには初級講座第48回 高度なメソッド・プロパティで説明しているOverloads(読み方:Overloads = オーバーロード)という技術が必要なのですが、使うだけなら簡単ですのでここで単純な例を紹介しておきます。

Form2の側に次のプロシージャを追加してください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Public Overloads Sub Show(ByVal UserName As String)

    MsgBox("パラメータとして" & UserName & "を受け取りました。")
    Me.Show()

End
Sub

■リスト12:Form2に書く。Showメソッドに独自の引数を追加する。

これでForm2をShowメソッドで呼び出すときにUserNameという文字列型のパラメータを送り込むことができるようになります。通常のメソッドと同じようにいくつでも引数を追加することが可能です。

使用例は次の通りです。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.Owner =
Me
f.Show("Visual Basic 中学校")

■リスト13:Form1に書く。独自引数付きのForm2のShowメソッドを呼び出す。

VB2005以上の場合ShowメソッドにはもともとOwnerを指定するための引数も用意されています。この引数も 生かしつつパラメータも追加するには次のようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Public Overloads Sub Show(ByVal Owner As IWin32Window, ByVal UserName As String)

    MsgBox("パラメータとして" & UserName & "を受け取りました。")
    Me.Show(Owner)

End
Sub

■リスト14:Form2に書く

 

5.モーダルフォーム

 

さて、今度は別の観点から2つのフォームの関係を眺めて見ます。Form1からForm2を表示させたときにForm2を閉じるまではForm1を操作できないようにしたい場合があります。

たとえば、メモ帳やExcelでは保存するファイル名を選択する画面を表示している間は文書の内容を変更できません。このように画面を閉じるまで親フォームが操作できなくなるような子フォームのことをモーダルフォーム、モーダルウィンドウなどと呼びます。(モーダルでない状態をモードレスと呼びます。)

つまり、Form2がモーダルであればForm2を閉じるまでForm1を操作できないということです。Form2をモーダルで表示させるのは実に簡単で、ShowメソッドではなくShowDialogメソッド(読み方:ShowDialog = ショウダイアログ)を使うだけです。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.ShowDialog()

■リスト15:Form1に記述する。

ShowDialogメソッドは引数を指定することもできて、引数に指定したフォームが自動的にOwnerプロパティにセットされます。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

f.ShowDialog(Me)

■リスト16:Form1に記述する。

 

メモ

VB2005の場合はShowのところで紹介したのと同様にもう一つの書き方可能です。しかし、Showと同じ理由でこの書き方はお勧めできません。

VB2005 対応


Form2.ShowDialog(Me)
 

■リスト17:Form1に記述する。

 

モーダルウィンドウはファイルの保存や設定の変更・確認などの作業に使われることが多いために呼び出し元フォームと連携するために特別な仕組みを持っています。

この仕組みとはShowDialogメソッドとDialogResultプロパティ(読み方:DialogResult = ダイアログリザルト)を組み合わせて使う方法のことです。

この仕組みを使うとForm2で、ユーザーは[OK]したのか、[キャンセル]したのかなどの情報を受け取ることができます。突然[OK]や[キャンセル]などと言われてもなんのことかと思うかもしれませんが、多くのソフトのダイアログ画面には[OK]とか[キャンセル]とか言うボタンがついていることを思い出してください。多くのソフトが使っている機能なので特別にそういう仕組みが用意されているのです。ですから、もしあなたのプログラムでは[OK]ボタンや[キャンセル]ボタンまたはそれに類する機能などないと言うのであればこの仕組みは必要ないかもしれません。

ともあれ、ここは1つ試しにこの機能を使ってみましょう。次のようにForm2をデザインしてください。

■画像9

[OK]ボタンにはbtnOK、[キャンセル]ボタンにはbtnCancelという名前をつけます。

さて、ここでForm2でテキストボックスに入力した文字がForm1のタイトルに表示されるようにします。ただし、Form2で[キャンセル]ボタンがクリックされたときはForm1のタイトルは変更されません。

Form1側のプログラムは次のようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As New Form2

If f.ShowDialog(Me) = DialogResult.OK Then
    Me
.Text = f.TextBox1.Text
End
If

■リスト18:Form1に記述する。

Form2側のプログラムは次のようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click

    Me.DialogResult = DialogResult.OK
   
Me.Close()

End Sub

Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click

    Me.DialogResult = DialogResult.Cancel
   
Me.Close()

End Sub

■リスト19:Form2に記述する。

Form2側で[OK]ボタンや[キャンセル]ボタンがクリックされたときにDialogResultプロパティにOKだとかCancelだとかの情報をセットしているのがポイントです。

このDialogResultプロパティにセットされた値をForm1側ではShowDialogメソッドの戻り値として受け取ることができます。

Form1側ではForm2が閉じられるまでShowDialogメソッドの行でプログラムの実行が停止し、次の行に進むことはありません。

このようにしてかなりシンプルに2つのフォームを連携させることができましたね。VB6ではこんなにシンプルにはできません。

ところが実のところ、上述のようなコードはそもそも書く必要すらないのです。上述のような書き方はプログラムを見れば何をやっているかわかるようになっているので私の好み ではあるのですが、本当に[OK]ボタンと[キャンセル]ボタンを単純に使うだけならばすべてをプロパティの設定だけで済ますこともできます。

Form2側のプログラム(btnOK_ClickbtnCancel_Click)を削除して、代わりにプロパティウィンドウでbtnOKDialogResultプロパティをOKに、btnCancelDialogResultプロパティをCancelにしてみてください。なんとこれだけで先ほどと同じ動作をさせることができるのです。ボタンをクリックしたらフォームを閉じるところまで自動でやってくれます。

ここまで自動化されたものをはじめから紹介してしまうと応用が利かなくなってしまうと思い後回しにしたわけですが、実際にどのような方法でプログラムするかは状況と好み次第です。

 

なお、先ほど紹介したOverloadsの手法を使えばShowDialogメソッドにも引数を追加することができます。説明が前後してしまいますがShowDialogメソッドに引数を追加する例も紹介しておきます。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Public Overloads Function ShowDialog(ByVal Owner As IWin32Window, ByVal UserName As String) As DialogResult

    MsgBox("パラメータとして" & UserName & "を受け取りました。")
    Return Me.ShowDialog(Owner)

End
Function

■リスト20:Form2に記述する。

この手法を使えばForm2が表示された時のTextBox1の初期値を設定することなどもできるようになります。

 

6.フォームのコレクション

 

VB2005以上ではアプリケーション全体に視点を移して現在開かれているすべてのフォームを取得する方法もあります。

Application.OpenFormsプロパティ(読み方:Application = アプリケーション、 OpenForms = オープンフォームズ)を使用すると現在開いているすべてのフォームのコレクションを取得できます。たとえば、次のようにすると現在開いているすべてのフォームの名前をリストボックスに表示できます。

VB2005 対応

For Each f As Form In Application.OpenForms
    ListBox1.Items.Add(f.Name)
Next

■リスト21

この仕組みは「すべてのフォーム」を列挙するのではなく、「すべての開いているフォーム」を列挙している点に気をつけてください。たとえば、Form2をまだ開いていない状態でApplication.OpenFormsにアクセスするとForm1だけが属していることになります。

また、Form1を1つ、Form2を2つ開いている状態では全部で3つのフォームがApplication.OpenFormsに属していることになります。

博士のワンポイントレッスン
V太 V太:博士〜。Form2を2つ開くってどういうことですか?
B子:よく読みなさいよ。リスト1のコードを何回も繰り返して実行すれば同じフォームをいくつでも開くことができるのよ。メモ帳だっていっぺんに一つしか開けないというわけじゃないでしょ。
B子には聞いてないやい。
博士 博士:Newは新しいインスタンスを作る機能なのじゃから、Newした数だけForm2が存在すると考えても良いな。もっともVB2005でForm2.ShowとやるとNewしなくても表示できてしまうんじゃが…。まぁこの機能は旧VB6プログラマへのサービス機能じゃな。VB6時代はこっちの方が標準だったのじゃ。

Application.OpenFormsを使用して個々のフォームを制御することもできます。たとえば、次の例では2番目の開いているフォームの背景色を青くします。

VB2005 対応


Application.OpenForms(1).BackColor = Color.Blue
 

■リスト22

ただ、「2番目」がどのフォームなのか分かっていないとあまり意味はありません。ですからこの方法では個々のフォームを制御するよりはすべてのフォームに対して一括して命令する場合の方が多いです。個々のフォーム同士の連携はやはりOwnerプロパティやOwnedFormプロパティを使用した方が便利です。

ところで、次の方法ですべてのフォームを閉じることはできません。

VB2005 対応

'これはエラーになる例です。
For
Each f As Form In Application.OpenForms
    f.Close()
Next

■リスト23:この例はエラーになる

すべての開いているフォームを列挙するというApplication.OpenFormsの意味とフォームを閉じるという行為が矛盾するからです。もうちょっとVB的に言うとコレクションの列挙中にコレクションの要素の構成を変更することができないからです。

すべてのフォームを閉じてプログラムを終了させたい場合には以下のようにApplication.Exitメソッド(読み方:Exit = エグジット)を使用します。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応


Application.Exit()
 

■リスト24

 

7.イベントの発生順序

 

次に2つ目のフォームを呼び出すときのイベントの発生順序を確認しておきます。イベントの発生の仕方がわからないと正しいタイミングでプログラムを実行することができませんから、こういったことは常に重要です。

細かいイベントの発生順序は後で紹介することにして、まずはイベントの活用方法を先にまとめます。

■図1

Newした時点ではForm2のNewが実行されるのみでイベントは発生しません。そこでフォームを表示する前に変数をセットするなどの作業が必要な場合はNewからShowまたはShowDialogの間に処理を記述するか、Newプロシージャ(つまりコンストラクタ)に処理を記述することになります。

ShowメソッドまたはShowDialogメソッドを実行してから実際に表示されるまでの間に発生する最も代表的なイベントはLoadです。表示直前に処理が必要であればLoadイベントに記述します。Activateイベントも発生しますがこのイベントは2つのフォームが表示されているときに片方のフォームがアクティブになったときに発生するのでShowまたはShowDialogのとき以外でも発生します。Activateイベントにはアクティブになるときに必要な処理を記述します。

VB2005では表示直後にShownイベント(読み方:Shown = ショウン)も発生します。

閉じるときの処理は通常通りなのでフォームが2つあるからといって特に注意することはありません。Form1側でForm2が閉じられたことを直接知るイベントはありません。

Form1側でForm2が閉じられたことを知りたい場合は、Form2のClosedイベントからForm1へ何かの方法で通知することになります。

以下に詳細なイベントの発生順序をまとめておきます。青い字で書いてある部分はVB2005でのみ発生するイベントです。

ShowDialogメソッド使用時 Showメソッド使用時 説明
Form1 Dim f As New Form2 を実行 Form1 Dim f As New Form2 を実行  
Form2New Form2New Form2のコンストラクタ実行
Form1 f.ShowDialog を実行 Form1 f.Show を実行  
Form2.HandleCreated Form2.HandleCreated Form2のハンドル生成
Form2.Load Form2.Load  
Form2.VisibleChanged Form2.VisibleChanged Form2を表示しようとする。
Form1.Deactivate Form1.Deactivate Form1がアクティブでなくなる。
Form2.Activated Form2.Activated Form2がアクティブになる。
Form2.Shown Form2.Shown Form2が表示される。
Form2 Me.Close を実行 Form2 Me.Close を実行  
Form2.Closing Form2.Closing Form2を閉じようとする。
Form2.FormClosing Form2.FormClosing  
Form2.Closed Form2.Closed Form2を閉じ終わる。
Form2.FormClosed Form2.FormClosed  
Form2.Deactivate Form2.Deactivate Form2がアクティブでなくなる。
Form1.Activate Form1.Activate Form1がアクティブになる。
Form2.VisibleChanged   Form2が非表示になる。
Form2.HandleDestroyed Form2.HandleDestroyed Form2のハンドルを破棄。
  Form2.Disposed Form2を破棄

■表1

参考 Visibleプロパティ

実はShowメソッドを使わなくてもForm2.Visible = TrueとするとShowメソッドと同等の効果があります。しかし、将来Form2の側がShowメソッドをオーバーライド(※1)するかもしれないのでこの方法はあまりお勧めできません。

また、ShowDialogメソッドでForm2を表示しているときに、Form2のVisibleプロパティをFalseにするとForm2を閉じた場合と似たような効果があります。しかしイベントの発生の仕方が微妙に変わってしまいますのでやはりお勧めできません。

※1 オーバーライド:メソッドの効果を上書きしてしまう技術。初級講座ではまだ登場していません。

 

 

8.その他の事柄

 

最後に2つ以上のフォームを使用する場合のその他の気になる事柄について少し触れておきます。

まず、プログラムが開始するフォームですが、既定では最初からあるフォーム(Form1)からプログラムが開始します。しかし、この設定はいくらでも変えることができます。はじめのフォームを変更するには[プロジェクト]メニューで[プロパティー]を選択し、「スタートアップの設定」でプロジェクトを開始するフォームを選択することができます。

この選択肢の中には「Sub Main」というフォームではない場所からプログラムを開始するというものもあります。Sub Mainについては別の機会に説明します。

スタートアップに指定されているフォームはただそこからプログラムが開始するというだけではなくプログラム全体を司る特別な役目があります。というのもこのスタートアップフォームが閉じられると連動してすべてのフォームが閉じられプログラム全体が終了するようになっているのです。

次に、たくさんのフォームが表示されている場合にFormクラスのActiveFormプロパティ(読み方:ActiveForm = アクティブフォーム)を使うと現在アクティブなフォームを取得できるという点も覚えておくと良いと思います。初級講座の現段階ではあまり使い道はありませんが将来複数のフォームやクラスを使いこなすようになると出番があります。次のコードはアクティブなフォームのタイトルバーに現在の時刻を表示します。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    Form.ActiveForm.Text = Now.ToString("hh:mm:ss")

End Sub

■リスト25

それから、すべての子フォームに対して命令する方法を紹介しておきます。前にも説明したようにOwnedFormsプロパティは子フォームの配列です。このプロパティとループを利用してすべての子フォームに対して命令を行うことができます。

ここでいう「子フォーム」とはそのOwnerプロパティの親フォームが設定されているものを指しています。

次のコードではすべての子フォームを閉じます。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim f As Form

For Each f In Me.OwnedForms
    f.Close()
Next

■リスト26