ユーザーフォーム入門
コントロールの動的作成

Excelマクロのユーザーフォームの基礎、エクセルVBAの入門解説
公開日:2020-01-06 最終更新日:2021-09-15

第22回.コントロールの動的作成


ユーザーフォームは、事前に画面デザインを考えて、それにそって部品コントロールを配置するものです。
しかし、ユーザーの操作に応じて、動的に部品コントロールを変更したい場合があります。


このような場合の対処方法としては、大きく以下の2通りの方法があります。
・部品コントロールの表示/非表示を切り替える
・動的に部品コントロールを追加/削除する

以下それぞれの方法について、具体的なVBAコードサンプルとともに解説していきます。


コントロールの動的作成の動作説明

初期

VBA マクロ ユーザーフォーム 動的コントロール

初期はコンボボックスだけの表示にします。
コンボボックスは1~5が選択できるようにします。

コンボボックスの選択

VBA マクロ ユーザーフォーム 動的コントロール

コンボボックスで選択した数値に応じてチェックボックスを表示します。

チェックボックスのチェック

VBA マクロ ユーザーフォーム 動的コントロール

チェックボックスをチェックするとテキストボックスを表示します。
チェックを外すとテキストボックスを消します。


コントロールの表示/非表示を切り替える

コントロールの表示/非表示を切り替えるには、以下の2通りの方法があります。
・Visibleプロパティの値をTrueで表示/Falseで非表示
・コントロールをフォーム外へ移動することで非表示/所定位置に移動することで表示

コントロールをフォーム外に移動して非表示にする方法は、少々裏技的な感じもしますが時々使われる手段なので覚えておくと良いでしょう。
以下では、Visibleプロパティの値を変更する方法でのVBAサンプルになります。

VBA マクロ ユーザーフォーム 動的コントロール

コントロールの名称

コンボボックス:cmb件数
チェックボックス:chk01~chk05
テキストボックス:txt01~txt05

フォームモジュール

モジュール名:何でも構いません。標準モジュールでの.Showに合わせてください。

Option Explicit

'初期処理
Private Sub UserForm_Initialize()
  With Me.cmb件数
    .Style = fmStyleDropDownList
    .List = Array(0, 1, 2, 3, 4, 5)
  End With
  Call ControlsUnVisibleAll
End Sub

'閉じるボタン
Private Sub btClose_Click()
  Unload Me
End Sub

'コンボボックスで数値を選択
Private Sub cmb件数_Change()
  Dim i As Long
  For i = 1 To Me.cmb件数.Value
    Me.Controls("chk" & Format(i, "00")).Visible = True
  Next
  Call ControlsUnVisible(Me.cmb件数.Value)
End Sub

'チェックボックスのチェックを変更
Private Sub chk01_Change()
  Me.txt01.Visible = Me.chk01.Value
End Sub
Private Sub chk02_Change()
  Me.txt02.Visible = Me.chk02.Value
End Sub
Private Sub chk03_Change()
  Me.txt03.Visible = Me.chk03.Value
End Sub
Private Sub chk04_Change()
  Me.txt04.Visible = Me.chk04.Value
End Sub
Private Sub chk05_Change()
  Me.txt05.Visible = Me.chk05.Value
End Sub

'指定数値以降のチェックボックスとテキストボックスを非表示
Private Sub ControlsUnVisible(Optional ByVal cnt As Long = 0)
  Dim i As Long
  For i = cnt + 1 To 5
    Me.Controls("chk" & Format(i, "00")).Visible = False
    Me.Controls("chk" & Format(i, "00")).Value = False
    Me.Controls("txt" & Format(i, "00")).Visible = False
  Next
End Sub

'全てのチェックボックスとテキストボックスを非表示
Private Sub ControlsUnVisibleAll()
  Dim ctl As Control
  For Each ctl In Me.Controls
    Select Case TypeName(ctl)
      Case "CheckBox", "TextBox"
        ctl.Visible = False
    End Select
  Next
End Sub

標準モジュールは、
フォームモジュール名.Show
これだけで良いです。
テストするだけならフォームモジュールでF5でも構いません。
実際に動かしながら、動作と対応するVBAコードを確認してみてください。


動的に部品コントロールを追加/削除する

動的に表示を切り替えるコントロールをVBAで追加/削除します。
VBAクラスでWithEventsを使います。
・Eventステートメント ・RaiseEventステートメント ・WithEventsキーワード ・標準モジュールと動作概要 ・ユーザーフォーム(UserForm1) ・クラス(clsEvent) ・クラスを使ったイベントの解説 ・VBAクラスを使ったイベントの最後に

VBA マクロ ユーザーフォーム 動的コントロール

コントロールの名称

コンボボックス:cmb件数

クラスモジュール

モジュール名:clsEvent

Option Explicit

'イベントを発生させるクラス(オブジェクト)
Private WithEvents pCheckBox As MSForms.CheckBox

'コントロールの親であるフォーム
Private pForm As MSForms.UserForm

'対応するコントロールを設定するプロパティ
Public Property Set CheckBox(ByVal aCheckBox As MSForms.CheckBox)
  Set pCheckBox = aCheckBox
  Set pForm = aCheckBox.Parent
End Property

'WithEventsのイベントプロシージャー
Private Sub pCheckBox_Change()
  Dim sNum As String
  sNum = Right(pCheckBox.Name, 2)
  
  Dim txt As MSForms.TextBox
  Set txt = GetTextBox(sNum)
  If txt Is Nothing Then
    Set txt = pForm.Add("Forms.TextBox.1", "txt" & sNum)
    With txt
      '以下の数値はサンプル画像で使った数値です
      .Top = sNum * 21 + 13
      .Left = 30
      .Height = 16.8
      .Width = 168
    End With
  End If
  
  txt.Visible = pCheckBox.Value
End Sub

'テキストボックスの存在確認:エラーを使った簡易コードにしています
Private Function GetTextBox(ByVal sNum As String) As MSForms.TextBox
  On Error Resume Next
  Set GetTextBox = pForm.Controls("txt" & sNum)
End Function

WithEventsのイベントプロシージャーは、
WithEvents変数名_イベント名
これはVBAの規則となっています。

また、WithEventsに指定するクラス(オブジェクト)の型に注意してください。
MSForms.CheckBox
このように、MSFormsのメンバを使わなければなりません。
単にCheckBoxではエラーとなります。

VBA マクロ コントロールの動的作成

フォームモジュール

モジュール名:何でも構いません。標準モジュールでの.Showに合わせてください。

Option Explicit

Private clsAry() As clsEvent

'初期処理
Private Sub UserForm_Initialize()
  With Me.cmb件数
    .List = Array(0, 1, 2, 3, 4, 5)
  End With
  ReDim clsAry(1 To 5)
End Sub

'閉じるボタン
Private Sub btClose_Click()
  Unload Me
End Sub

'コンボボックスで数値を選択
Private Sub cmb件数_Change()
  Dim ctl As Control
  Dim max As Long
  Dim num As Long
  max = Me.cmb件数.Value
  For Each ctl In Me.Controls
    If IsNumeric(Right(ctl.Name, 2)) Then
      num = Right(ctl.Name, 2)
      If num > max Then
        'コントロールの削除
        Me.Controls.Remove ctl.Name
      End If
    End If
  Next
  
  'チェックボックスの動的追加
  For num = 1 To max
    Call AddCheckBox(num)
  Next
End Sub

'チェックボックスの動的追加
Private Function AddCheckBox(ByVal num As Long) As MSForms.CheckBox
  'チェックボックスの存在確認
  Set AddCheckBox = GetCheckBox(num)
  If Not AddCheckBox Is Nothing Then Exit Function
  
  'チェックボックスをフォームに追加
  Dim sName As String
  sName = "chk" & Format(num, "00")
  Set AddCheckBox = Me.Controls.Add("Forms.CheckBox.1", sName)
  With AddCheckBox
    .Top = num * 21 + 13
    .Left = 10
    .Height = 16.8
    .Width = 18
    .Caption = ""
  End With
  
  '追加したチェックボックスをクラスに設定
  Set clsAry(num) = New clsEvent
  Set clsAry(num).CheckBox = AddCheckBox
End Function

'チェックボックスの存在確認
Private Function GetCheckBox(ByVal num As Long) As MSForms.CheckBox
  On Error Resume Next
  Set GetCheckBox = Me.Controls("chk" & Format(num, "00"))
End Function

標準モジュールについては、
フォームモジュール名.Show
これだけで良いです。
テストするだけならフォームモジュールでF5でも構いません。
実際に動かしながら、動作と対応するVBAコードを確認してみてください。


コントロールの動的作成の最後に

上記で2通りの方法を紹介しましたが、
基本的には、「コントロールの表示/非表示を切り替える」こちらの方法が良いでしょう。

チェックボックスの数を増減させたい場合でも、
画面に収まる範囲内で同時に表示できる数には限度がありますし、最大数は決まっているはずです。
最大数をあらかじめ配置しておき、表示/非表示での切替と位置移動だけで全て対応できます。

何より、よりきめ細かい動作をさせようとすると、動的な追加ではVBAが複雑になりデバッグが大変になってしまいます。
とはいえ、コントロールの動的追加はユーザーフォームを扱う上では必要な技術ですので、いざと言う時に使えるように習得しておくと良いでしょう。




同じテーマ「ユーザーフォーム入門」の記事

第18回.2段階のコンボボックス
第19回.数値専用のテキストボックス
第20回.テキストボックスの各種イベント
第21回.ユーザーフォームの各種イベント
第22回.コントロールの動的作成
第23回.イベントプロシージャーの共通化
第24回.イベントプロシージャーの共通化(Enter,Exit)
第25回.簡易音楽プレーヤーの作成
第26回.プログレスバーを自作する
第27回.インクリメンタルサーチの実装
第28回.テンキーのスクリーンキーボード作成


新着記事NEW ・・・新着記事一覧を見る

ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
累計を求める数式あれこれ|エクセル関数応用(2024-01-22)
複数の文字列を検索して置換するSUBSTITUTE|エクセル入門(2024-01-03)
いくつかの数式の計算中にリソース不足になりました。|エクセル雑感(2023-12-28)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.RangeとCellsの使い方|VBA入門
4.ひらがな⇔カタカナの変換|エクセル基本操作
5.繰り返し処理(For Next)|VBA入門
6.変数宣言のDimとデータ型|VBA入門
7.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
8.並べ替え(Sort)|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.Findメソッド(Find,FindNext,FindPrevious)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。


このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ