ユーザーフォームへのコントロールの動的配置
コンボボックスを動的に追加する
フォームにコンボボックスを追加する
コンボボックスやリストボックスは、ユーザからの入力を受け付けるインターフェースとしては便利なんだが、チマチマ作ることを思うと結構メンドクサイ。
コンボボックスの追加がラクにできたらいいなあ、と思い、ちょっと実験してみた。
まずは、フォームを挿入する。今回はオブジェクト名を「FormTest02」としてある。
リスト1 フォームモジュール
Private srcRange_() As Range '……(*)' Private cmbBox_() As MSForms.ComboBox Private numOfCombos_ As Integer Public Sub createComboBox( _ ByVal posTop As Double, _ ByVal posLeft As Double, _ ByVal meHight As Double, _ ByVal meWidth As Double, _ ByVal srcRange As Range) '……(1)' numOfCombos_ = numOfCombos_ + 1 '……(2)' ReDim Preserve srcRange_(numOfCombos_ - 1) Set srcRange_(numOfCombos_ - 1) = srcRange ReDim Preserve cmbBox_(numOfCombos_ - 1) '……(3)' Set cmbBox_(numOfCombos_ - 1) = _ Controls.Add("Forms.ComboBox.1", "cmbBox" & numOfCombos_, True) '……(4)' With cmbBox_(numOfCombos_ - 1) '……(5)' .top = posTop '……(6)' .left = posLeft .height = meHight .width = meWidth Dim i As Integer For i = 0 To srcRange_(numOfCombos_ - 1).Rows.Count - 1 '……(7)' .AddItem srcRange.Cells(i + 1, 1).Value Next End With End Sub
まずは、宣言セクションの(*)からの3行
Private srcRange_() As Range Private cmbBox_() As MSForms.ComboBox Private numOfCombos_ As Integer
3つのPrivate変数を宣言。
srcRange_は、コンボボックスのデータソースになるセル範囲を入れておく変数。複数になることを想定して配列にしている。
cmbBox_()は、動的に生成したコンボボックスを格納しておく変数。これまた複数になることを想定して配列にしている。
numOfCombos_は生成されたコンボボックスの数を記録するための変数。
(1)では、コンボボックスを生成するためのcreateComboBoxメソッドを定義。
とりあえず5つの引数を受け取ってコンボボックスを作成することにする。
それぞれの引数の役割は、以下の通り。
- ・posTopはフォーム上のタテ位置。
- ・posLeftはフォーム上のヨコ位置。
- ・meHeightはコンボボックスの高さ。
- ・meWidthはコンボボックスの幅。
- ・srcRangeはデータソースになるセル範囲。
実際にはもっと細かく指定しないと使い物にならないけれど、今回はとりあえずの実験なのでこのぐらいで勘弁してほしい。
(2)の
numOfCombos_ = numOfCombos_ + 1
では、このメソッドが呼び出されるごとにnumOfCombos_をインクリメント。こうすることで、生成されたコンボボックスを番号で指定できるようにする。
(3)の
ReDim Preserve cmbBox_(numOfCombos_ - 1)
で、生成したコンボボックスを格納するための配列変数をReDimする。前に格納していたコンボボックスが消えないように、Preserveしている。
(4)の
Set cmbBox_(numOfCombos_ - 1) = _ Controls.Add("Forms.ComboBox.1", "cmbBox" & numOfCombos_, True)
では、ControlsコレクションのAddメソッドを用いて、配列変数cmbBox_()に新たに生成したコンボボックスを格納。
Newできたら分かりやすいのになあ。
(5)からは、
With cmbBox_(numOfCombos_ - 1)
このように、「cmbBox_(numOfCombos_ - 1)」をWithで括ることによって、新たに追加したコンボボックスへの設定を行う。
ただし、(6)からの4行
.top = posTop .left = posLeft .height = meHight .width = meWidth
なんかヘンだと思いませんか?
実は、インテリセンスが働かず、
このように入力候補にも出てこないのです。
んで、改行しても頭文字が小文字のまま。メチャクチャ不安になりますな。
あとは、(7)からの3行
For i = 0 To srcRange_(numOfCombos_ - 1).Rows.Count - 1 .AddItem srcRange.Cells(i + 1, 1).Value Next
AddItemメソッドでドロップダウンリストにsrcRangeからデータを追加している。
ホントは、Listプロパティを設定して複数列リストに対応しないといけないんだけれど、今回は実験ということで1列で勘弁してほしい。
実行
標準モジュールに次のコードを書いて実行する。
リスト2 標準モジュール
Public Sub exhibition() Dim frm As TestForm02 '……(1)' Set frm = New TestForm02 With frm .createComboBox 10, 30, 20, 80, ActiveSheet.Range("B2:B7") '……(2)' .createComboBox 10, 130, 20, 80, ActiveSheet.Range("C2:C7") .Show '……(3)' End With End Sub
まず、(1)からの2行
Dim frm As TestForm02 Set frm = New TestForm02
TestForm02型の変数frmにTestForm02のインスタンスを格納。
(2)からの2行は、WithでまとめているのでいづれもTestForm02のインスタンスに対する処理。
.createComboBox 10, 30, 20, 80, ActiveSheet.Range("B2:B7") .createComboBox 10, 130, 20, 80, ActiveSheet.Range("C2:C7")
createComboBoxメソッドを、引数を変えて2回呼び出している。
で、(3)の
.Show
でフォームを表示しておしまい。
実行結果
このように2つのコンボボックスが設置されたフォームが表示され、
左側のコンボボックスにはB列のデータが、
右側のコンボボックスにはC列のデータが入っている。
おわりに
これだけではまるで使い道がないし、使い物になるコンボボックスにするためには設定すべきプロパティがメチャクチャたくさんあるので、普通にメソッドに引数を渡すような実行方法は現実的でないと思う。
たとえば、ワークシートにコンボボックスの細かい仕様を表す表を作成しておいて、そこから値を読み込んでプロパティを設定するというやり方になりそうだ。
あと、イベントを検知できなければ使い物にならないので、WithEventsキーワードの使い方についてもこれから研究していく必要がある。
けっこう面白いかも知れないなあ。