ユーザーフォームへのコントロール配置――ControlsコレクションのAddメソッド
ユーザーフォームへのコントロール配置――ControlsコレクションのAddメソッド
ControlsコレクションのAddメソッドによるコントロールの動的配置
この本の162ページによると、
ユーザーフォームにコントロールを追加するには、Controlsコレクション(集合体)のAddメソッドを使います。第1引数には、コントロールのクラス文字列を指定します。第2引数はコントロール名を指定します。
とのこと。ふむふむ、なるほど。
んで、
クラス文字列
については、同書184ページによると、
コントロール | クラス文字列 |
---|---|
コマンドボタン | Forms.CommandButton.1 |
テキストボックス | Forms.TextBox.1 |
ラベル | Forms.Label.1 |
コンボボックス | Forms.ComboBox.1 |
リストボックス | Forms.ListBox.1 |
チェックボックス | Forms.CheckBox.1 |
オプションボタン | Forms.OptionButton.1 |
イメージ | Forms.Image.1 |
トグルボタン | Forms.ToggleButton.1 |
スクロールバー | Forms.ScrollBar.1 |
スピンボタン | Forms.SpinButton.1 |
タブストリップ | Forms.TabStrip.1 |
マルチページ | Forms.MultiPage.1 |
とのこと。(ふう。しっかしHTMLで表書くのしんどいな。)
つまり、
Dim ctrl As Control Set ctrl = Controls.Add("Forms.CommandButton.1","BtnHogeHoge")
としてやれば、「BtnHogeHoge」という名前のCommandButtonコントロールを追加することができる、ということだ。
で、やってみた。
前回
のフォーム及びコードを流用する。
まずは、前回のリスト1の書き換えから。
リスト1 フォームモジュール
Public Sub init_ver2(ByVal numOfBtns As Integer, _ ByVal btnHeight As Double, _ ByVal btnWidth As Double, _ ByVal offsetBtnsRow As Double, _ ByVal offsetBtnsCol As Double, _ ByVal numOfCols As Integer, _ ByVal btnName As String) numOfBtns_ = numOfBtns Dim i As Integer Dim ctrl As Control '……(1)' For i = 1 To numOfBtns_ Set ctrl = Controls.Add("Forms.CommandButton.1", _ "Btn" & Format(i, "0#")) '……(2)' With ctrl .height = btnHeight .width = btnWidth .Top = offsetBtnsRow + ((offsetBtnsRow + btnHeight) * ((i - 1) \ numOfCols)) .Left = offsetBtnsCol + ((offsetBtnsCol + btnWidth) * ((i - 1) Mod numOfCols)) .Caption = btnName & StrConv(i, vbWide) & "号" End With Next With Me .height = offsetBtnsRow _ + ((btnHeight + offsetBtnsRow) * (((numOfBtns_ - 1) \ numOfCols) + 1)) _ + TOP_BOTTOM_MARGIN .width = offsetBtnsCol + ((btnWidth + offsetBtnsCol) * numOfCols) + offsetBtnsCol End With End Sub
変えたのは(1)からの12行(実質11行)
Dim ctrl As Control For i = 1 To numOfBtns_ Set ctrl = Controls.Add("Forms.CommandButton.1", _ "Btn" & Format(i, "0#")) '……(2)' With ctrl .height = btnHeight .width = btnWidth .Top = offsetBtnsRow + ((offsetBtnsRow + btnHeight) * ((i - 1) \ numOfCols)) .Left = offsetBtnsCol + ((offsetBtnsCol + btnWidth) * ((i - 1) Mod numOfCols)) .Caption = btnName & StrConv(i, vbWide) & "号" End With Next
Control型の変数に、ControlsコレクションのAddメソッドを用いて、新しいボタンをセット。With以下のところは前回同様。Forループでボタンの数だけ繰り返している。
(2)の
Set ctrl = Controls.Add("Forms.CommandButton.1", _ "Btn" & Format(i, "0#"))
が今回の主役。
Addメソッドの第1引数に、コマンドボタンのクラス変数「Forms.CommandButton.1」を指定。最後の「1」まで必要なので注意。最初、オブジェクトの通し番号だと思って
Controls.Add("Forms.CommandButton." & i,"Btn" & Format(i, "0#"))
と書いて、i = 2 になったところでエラーが出たw
第2引数では、変数 i を用いて、名前が「Btn01」、「Btn02」、……となるようにした。
実行
ついでに実行方法も変更した。
ワークシート上に、こんなふうにボタンと表を作って、次のコードで実行するようにした。
リスト2 標準モジュール
Public Sub controlTest2() Dim testFrm As TestForm Set testFrm = New TestForm Dim num As Integer Dim str As String Dim height As Double Dim width As Double Dim frmName As String Dim numOfButtons As Integer With ActiveSheet '……(1)' num = .Range("C2").Value str = .Range("C3").Value height = .Range("C4").Value width = .Range("C5").Value frmName = .Range("C6").Value numOfButtons = .Range("C7").Value End With If num = 0 Or num > 10 Then Exit Sub '……(2)' If height < 10 Or height > 400 Then Exit Sub If width < 10 Or width > 400 Then Exit Sub If numOfButtons < 1 Or numOfButtons > 100 Then Exit Sub With testFrm .init_ver2 numOfBtns:=numOfButtons, _ btnHeight:=height, _ btnWidth:=width, _ offsetBtnsRow:=10, _ offsetBtnsCol:=5, _ numOfCols:=num, _ btnName:=str .Caption = frmName .Show End With End Sub
(1)からの8行
With ActiveSheet num = .Range("C2").Value str = .Range("C3").Value height = .Range("C4").Value width = .Range("C5").Value frmName = .Range("C6").Value numOfButtons = .Range("C7").Value End With
で、init_ver2メソッドに渡す引数のうち5つと、フォームのCaptionプロパティに渡す文字列をシートから取得する。
変数の名前を見てもらったら、どれが何に当たるかは分かると思う。
(2)からの4行
If num = 0 Or num > 10 Then Exit Sub If height < 10 Or height > 400 Then Exit Sub If width < 10 Or width > 400 Then Exit Sub If numOfButtons < 1 Or numOfButtons > 100 Then Exit Sub
はガード節。不適切な値が設定されていたら処理をやめるようにしている。
ただし、条件設定はかなりテキトー。
実行結果
なんと、最初に設置した10個のコマンドボタンが設置されたまま、今回、Addメソッドで追加したコマンドボタンが上から配置されている……。
試しに、リスト1の最後に
For Each ctrl In Controls Debug.Print ctrl.name Next
を追加して実行してみると、イミディエイト・ウインドウは、
こうなる。
どうやら、「Btn01」とか「Btn02」というのは「オブジェクト名」のことではないらしい。ま、当たり前か。
こんなふうに、もともと置いてあったコマンドボタンを全部削除してから実行すると、
無事、思い通りの結果が得られた。
おわりに
ついついムキになってユーザーフォーム・コントロール関係にハマってしまったが、実用的なものにするには、動的に配置したコントロールのイベントをどうするか、ということだと思う。ただ、ちょっとまだ今の私の力では手に負えない気もする。
まだまだ勉強が足りないね。