皆さんはExcel VBAでユーザーフォームを使用していますか?
ユーザーフォームを使うことで、視覚的に見やすい機能を実現できたり、ユーザーがデータを入力しやすくなるなどメリットがあります。
一方で、自由度が高いが故に、ある程度の経験がないと実用的なものを作るのが難しかったり、人によって癖が出やすいため保守が困難になったりもします。
ここでは、オブジェクト指向プログラミングにすることで、コードの再利用性や保守性が向上する点に着目し、ユーザーフォームにもこれを取り入れることで、上記の障害を緩和する方法を紹介します。
①今回の題材
下記のように「SampleForm」というユーザーフォームを作るとします。
コンボボックスとラベルを1つずつ置いています。

Sheet1にコンボボックスに登録したい文字列を入力しておくことにします。

マクロを起動すると「SampleForm」が立ち上がり、Sheet1のB3セル以下にある値がコンボボックスに追加されます。
また、コンボボックスで選択した値が下のラベルに反映されるようにします。
以上が、今回の題材となるユーザーフォームの仕様です。
②一般的なユーザーフォームの使い方
一般的には下記のような実装になるかと思います。
・ユーザーフォーム側の実装
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
'*************** 定数を定義 ***************** Const START_ROW As Long = 3 '開始行番号 Const TARGET_COLUMN As Long = 2 '対象列番号 '*************** 実行 *************** Private Sub cmbSample_Change() 'コンボボックスで選択した値をラベルに反映 Me.lbSample.Caption = Me.cmbSample.Value End Sub '*************** 初期化 ********************* Private Sub UserForm_Initialize() 'Sheet1のB列に入力されている最終行を取得 Dim lastRow As Long lastRow = Sheet1.Cells(Sheet1.Rows.Count, TARGET_COLUMN).End(xlUp).Row 'Sheet1の開始行から最終行までB列の値をコンボボックスに追加 Dim targetRow As Long For targetRow = START_ROW To lastRow Me.cmbSample.AddItem Sheet1.Cells(targetRow, TARGET_COLUMN).Value Next targetRow 'コンボボックス選択の初期化 Me.cmbSample.ListIndex = 0 'ラベルの値の初期化 Me.lbSample.Caption = "初期値です" End Sub |
・標準モジュール側の実装
(「SampleModule」に「showUserForm」プロシージャを作った場合)
|
1 2 3 4 |
'************* メイン処理 ************* Sub showUserForm() SampleForm.Show End Sub |
ユーザーフォームを起動するだけなので、これだけです。
下記のとおり実行して結果を確認してみます。
マクロからshowUserFormを選んで実行すると下記のユーザーフォームが表示されます。
ラベルの値は「初期値です」となっています。

コンボボックスのドロップダウンリストで「守山」を選択します。

ラベルの値が「守山」に変わりました。

③オブジェクトとしての使い方
続いて、ユーザーフォームをオブジェクトとして扱う場合です。
今回はユーザーフォーム側のInitializeを削除し、メイン処理側で初期化するようにしてみます。
②のUserForm_Initialize内のコードを標準モジュール側に移植したような形になります。
・ユーザーフォーム側の実装(オブジェクト使用)
|
1 2 3 4 5 |
'*************** 実行 *************** Private Sub cmbSample_Change() 'コンボボックスで選択した値をラベルに反映 Me.lbSample.Caption = Me.cmbSample.Value End Sub |
・標準モジュール側の実装(オブジェクト使用)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
'*************** 定数を定義 ***************** Const START_ROW As Long = 3 '開始行番号 Const TARGET_COLUMN As Long = 2 '対象列番号 '*************** メイン処理 ***************** Sub showUserForm() 'Sheet1のB列に入力されている最終行を取得 Dim lastRow As Long lastRow = Sheet1.Cells(Sheet1.Rows.Count, TARGET_COLUMN).End(xlUp).Row 'SampleFormオブジェクトを生成 Dim fm As SampleForm Set fm = New SampleForm 'Sheet1の開始行から最終行までB列の値をコンボボックスに追加 Dim targetRow As Long For targetRow = START_ROW To lastRow fm.cmbSample.AddItem Sheet1.Cells(targetRow, TARGET_COLUMN).Value Next targetRow 'コンボボックス選択の初期化 fm.cmbSample.ListIndex = 0 'ラベルの値の初期化 fm.lbSample.Caption = "初期値です" 'ユーザーフォームを表示 fm.Show 'オブジェクトの解放 Set fm = Nothing End Sub |
実行結果は②と同じなので割愛します。
一番のポイントはSet fm = New SampleFormの箇所です。オブジェクト変数の場合はSetステートメントが必要なのでご注意ください。
最後にオブジェクト解放もしておきます。
今回の題材の場合は恩恵が感じられませんが、ユーザーフォームに外部のモジュールから値を渡す際に、グローバル変数を使用する必要がなかったり、同じユーザーフォームを違う機能として使いたい場合など多くのメリットがあります。
④おわりに
今回は、ユーザーフォームをオブジェクトとして扱う方法を紹介しました。
ここでは、オブジェクトにする具体的なメリットについては次の記事に書いています。
以上、最後まで読んでいただき、ありがとうございました。

コメント