コントロール配列を使う
VBで扱うことのできるコントロール配列というのは、非常に便利なものです。
VBのサンプルに、"Calc"というプロジェクトがありますが、これはコントロール配列の最もベーシックな使い方、つまりデザイン時のコントロール配列の作り方を説明しています。
しかし、コントロール配列の使い方はこれだけではありません。今回はプログラムの実行中に動的にコントロールを生み出す方法について解説します。
動的なコントロールの生成というのは、実践的なプログラムを作る上で非常に重要なテクニックです。私はドロー系のプログラムを作る際にこの手法を用いました。皆さんも是非マスターしてください。
今回の講座のサンプルは、 ここを押すとダウンロード
できます。
例題のフォームはこんな感じです。
ボタン"FormAppend"を押すとフォームのコピーが生成され、"Hide"を押すとHide
メッソドを実行し、"Unload"でフォームをアンロードします。そして、"ContAppend"
でラベルコントロールを追加します。
Public FormX() As New Form1 'Main.bas
変数宣言
Public FormCnt As Integer
Sub Main()
Form_Append
Unload Form1
End Sub
いきなりForm1をUnloadしているのは何故でしょうか?
次を見てみましょう。
Sub Form_Append() 'MainBas
FormCnt = FormCnt + 1
ReDim FormX(1 To FormCnt)
FormX(FormCnt).Caption = "Forms of " + Str(FormCnt)
FormX(FormCnt).Show
End Sub
Form_Appendでは、フォームのカウンタを増やして新しいフォームを作っています。
ここで、先ほどの宣言を見てみると、
Public FormX() As New Form1
となっています。フォームを配列化して動的に生成するときはこう宣言して、
ReDim FormX(カウンタ値)
とするだけで作られます。ただし、フォームをShowしないと画面上には現れてきません。
ここで、Main関数でForm1をUnloadしていたことを思い出して下さい。
新しく作られたフォームは、FormX(1)とかFormX(2)...FormX(n)というように、
FormX(フォームの番号)という名前で参照できますし、こうしておく方がプログラムが簡単になります。そのため、Form1を削除しているのです。
また、添字が1から始まるようにしているのもプログラミングとデバッギングのためです。
ボタン"FormAppend"は、Form_Appendを呼んでいるだけです。
Private LabelCnt As Integer 'Form1.frm 変数宣言
Private LabelTop As Long
Private Sub Command2_Click() 'Hide ボタン
Me.Hide
End Sub
Hideボタンで実行しているメソッドは、
Me.Hide
ですが、Meといのは便利な変数で、HELPファイルにはこう書かれています。
キーワード Me は、複数のインスタンスを作成できるクラスを使用するときに、現在コードが実行されているクラスを指定するために使われます。
難しいことが書かれていますが、要するにMeとはここではForm(n)自身を表しているのです。つまり、プログラムは「何番目のフォームのボタンが押されたか?」ということを意識することなく、Meだけで現在のフォームに対しての操作を行えるのです。
では、自分(アクティブなフォーム)が何番目のフォームかを知りたい時はどうすれば良いでしょう?
Me.Hwnd と FormX(n).Hwnd を比較すれば分かります。
Private Sub Command3_Click() 'Unload ボタン
Unload Me
End Sub
UnLoadとHideの動作は一見似ていますが、大きな違いがあります。
フォームを1つだけ表示した状態で、UnLoadとHideを試してみて下さい。
Unloadの場合はプログラムが終了しますが、Hideの場合は終了しませんね?
これはプログラムをexe化する場合に特に大事なことです。
Private Sub Command4_Click() 'ContAppend ボタン
LabelCnt = LabelCnt + 1
Load Label1(LabelCnt)
Label1(LabelCnt).Top = LabelTop + Label1(LabelCnt).Height
Label1(LabelCnt).Caption = "Label" + Str(LabelCnt)
Label1(LabelCnt).Visible = True
LabelTop = Label1(LabelCnt).Top
End Sub
ContAppendボタンでは、ラベルコントロールの作成をしています。
ここで注意することは、デザイン時にコントロールのプロパティ設定でIndexを0にしておくことです。これでVBはそのコントロールが配列化されたコントロールであると認識してくれるのです。
後は、インデックスを増やしてLoadしてやればコントロールが生成されます。
さて、ここで問題です。
フォームが幾つか表示されている状態でContAppendボタンを押すと、確かにそのフォームの上にラベルが追加されます。プログラム上ではフォームの違い等を意識した部分はないのに、なぜアクティブなフォーム上に追加されるのでしょうか?
答えは簡単で(いや、説明しだすと複雑になってしまいますが)、フォームを新たに追加したときにデザイン時に乗っかているコントロールやそれぞれのプロパティ、メッソドなどがそっくりコピーされて新しいフォームが作られるからです。
このことをオブジェクト指向の概念で継承といいます。
つまり、Form1.frmの中身がそっくりコピーされたクローンのようなフォームが作られたからで、Form1.frm、Form2.frm、Form3.frm...と別々に作ったのと同じ効果が得られるのです。
ただし、継承されるのはあくまでデザイン時の状態です。ラベルを幾つか追加した状態でフォームをAppendすればこのことが確認できます。
また、Formと他のコントロールでは配列の実現方法が違うことにも注意して下さい。
最後に
以上でコントロール配列の解説は終わりです。
フォームの配列化は、MDI形式のプログラムを実現する場合に重要なことです。
また、フォーム以外のコントロールの配列はビジュアルなインターフェイスを作る上で重要です。
コントロールに限らず、配列を使いこなすということはプログラミングにおいて避けては通れない試練です。特にVBのコントロール配列は非常に扱いやすくなっています。
また、ヘルプの引用にもありましたが、フォームやコントロールなどのオブジェクトはクラスです。これはオブジェクト指向の要ともいえる概念なのですが、VBでは難しい概念を理解していなくても上記のようにクラスの継承などの恩恵に預かれることができるのです。