VBA

【VBAユーザーフォーム:動的にコントロールを追加する】

VBA ユーザーフォーム

皆さんの中に、ExcelVBAのフォームで、コントロールを動的に作成していくことってできないのかなと考えている方がいるかもしれません。

今回は、そんな方の為に、難しい技術ですが解説を書いていきたいと思います。

クラスモジュールを使うことでイベントも拾えるので、使い道は色々とあるかと思います。

クラスモジュール

VBAをバリバリ使用している方でも、クラスモジュールって何?となっている方が多いと思います。
そこで、クラスモジュールの説明から書いていきたいと思います。
クラスモジュールを理解されている方は、読み飛ばしてください。

クラスとは

オブジェクトを作成するためのデータ型です。その「型」を好きなように作成できます。オブジェクトはすべて参照型になります。

ワークシートや、セルを表す Range などのオブジェクトは、すべてクラスで作成されています。

標準モジュールと同じように、変数や関数といったコードを書けます。その他にコンストラクタやプロパティといったクラス専用の機能があります。

インスタンス化するとクラスが使用できるようになります。使い終わったらインスタンスを、破棄する必要があります。

クラスのインスタンス化とは

クラスは、オブジェクト指向のプログラムでは非常に重要な考え方ですので、イメージを固めていただければと思います。

クラスからオブジェクトを生成することを「インスタンス化」と言います。

クラスが「型」で、その「実体」がインスタンスである


あるいは、クラスは「設計図」「定義」「テンプレート(雛形)」などとも説明されることもあります。

プログラムでの記述方法としては、newというキーワードを使い、 「new クラス名」と記述します。

'オブジェクト型の変数にClass1を代入しています(インスタンスの生成)
Sub インスタンスの生成1()
    Dim myClass As Object
    Set myClass = New Class1
End Sub
'変数の宣言時にNew
Sub インスタンスの生成2()
    Dim myClass As New Class1
End Sub

上記コードどちらでもインスタンス化できます。
クラス及び、オブジェクト指向はVBAだけやっていると理解しにくいと思いますので、今後詳しく解説していきます。

実装

それでは実装していきます。

クラスモジュール

まずクラスモジュールを一つ追加して以下のコードを張り付けてください。

Option Explicit

Private WithEvents myBtn As MSForms.CommandButton

Public Property Set Btn(ByVal myNewBtn As MSForms.CommandButton)
    Set myBtn = myNewBtn
End Property

Private Sub myBtn_Click()
    MsgBox "[" & myBtn.Caption & "]ボタンがクリックされました。" _
        , vbInformation
End Sub

クラスモジュールには追加するボタンのクリック処理をサンプルとして用意しました。

追加されたボタンはmybtnに格納されます。

あまり見慣れない、Propertyプロシージャや、WithEventsキーワードが出てきていますが、解説すると長くなるので今回は省略します。

VBAでのオブジェクト指向の解説を行う際に丁寧に解説します。

ユーザーフォーム

ユーザーフォームを一つ作成して、ボタンを一つ追加してください。

名前はデフォルトのままで構いません。

ボタンをダブルクリックして、下記コードを張り付けてください。

Option Explicit

Private Sub CommandButton1_Click()
    Static myCollection As New Collection
    Dim myCmdBtn As MSForms.CommandButton
    Dim myClass As Class1
    Dim myCnt
    Set myCmdBtn = Controls.Add("Forms.CommandButton.1")
    myCnt = myCollection.Count
    With myCmdBtn
        .Left = 18 + (myCnt \ 5) * 72
        .Top = 18 + (myCnt Mod 5) * 24
        .Accelerator = CStr(myCnt)
        .Caption = "追加ボタン(" & .Accelerator & ")"
    End With
    Set myClass = New Class1
    Set myClass.Btn = myCmdBtn
    myCollection.Add myClass
    myCnt = myCnt + 1
    If myCnt = 10 Then CommandButton1.Enabled = False
    Set myClass = Nothing
End Sub

標準モジュール

最後に標準モジュールには、ユーザーフォームを表示するコードを書きます。

Option Explicit

Sub ShowForm()
    UserForm1.Show
End Sub

実行してみる

ShowFormメソッドを実行してフォームを表示してみてください。

表示後に「ボタン追加(A)」をクリックしてみてください。
クリックした回数だけボタンが増えると思います。

次に追加ボタン(0)など追加されたボタンを押してみてください。

ボタンのCaptionがメッセージボックスで表示されると思います。
()内の数字が押すボタンにより変更されていることが分かると思います。

今回のまとめ

いかがでしたか?
今回のサンプルは、そのままでは実用性はありませんが、応用していろいろなコントロールを使用する事で、かなり便利な使い方が出来るのではないでしょうか。

クラスを使用する事で、コードの可読性が上がりバグなどが発生しにくく、メンテナンス性の高いコードが出来ます。

クラス化することで、コードの再利用性も非常に高くなり、使い捨てコードを減らすことも可能です。

VBAのクラスは貧弱なので、使いたがらない人も多いですが、 当ブログでは、どんどんクラスを使っていきたいと思います。

最後まで読んでいただき、ありがとうございます。

オブジェクト指向を取り上げている書籍はVBAでは少ないです。

C#やVB.NETなどの書籍を読むと記載があります。

ぜひVBAに読み替えてC#などの書籍も読んでみると出来ることが一気に増えるかと思います。

複数の言語を学ぶことで、プログラミング力が飛躍的に向上するのでC#の本も読んでみてください。