ユーザーフォーム独自イベント。Spinボタンで数量±2する。

Spinボタンで数量±2するためには…

以下の動画をご覧ください。

数量1がSpinボタンで±2されています。この処理を実装するためには、UserFrom上にSpinボタンを作成して、SpinUp、SpinDownイベントに±2するように記述すればいいと思われるでしょう。

しかし、このユーザーフォームには以下の画像の通り、Spinボタンはありません。
f:id:bimori466:20201114220553p:plain

つまり、ユーザーフォーム上には実体がないため、SpinボタンのSpinup、SpinDownイベントに記述することができません。


仮に、実体があれば以下のコードで実装が可能。
f:id:bimori466:20201114221319p:plain

Private Sub spn_数量_Spinup()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value + 2

End Sub
'--------------------------------------------------------------------------------------
Private Sub spn_数量_SpinDown()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value - 2

End Sub


しかし、今回のように動的に作成したコントロールに対してイベント処理をさせるにはどうすればいいのか。それはクラスモジュールの「WithEvents」を使います。
その設定方法について解説します。

1 閲覧対象者

クラスモジュールの「WithEvents」を使ってユーザフォームコントロールに、独自のイベント処理を追加する方法を学びたい方。

2 得られる効果

自分のやりたい処理(独自の処理)を実装できる。
大量のコントロールがある場合に、コントロール1つ1つに対してイベント処理を書かなくてよい(共通化できる)。

3 設計

動的に作成したSpinボタンに対して、クラスモジュールの「WithEvents」を使って、Spinup、Spindownで、TextBoxの数量1を±2する独自イベントを作成する。

<1 ユーザーフォーム フォームコントロール画面>

f:id:bimori466:20201114222904p:plain


<2 ユーザーフォーム コード>

'UserFromのコレクションの宣言(独自イベントの登録用コレクション)
Private CheckCollection As Collection
'--------------------------------------------------------------------------------------

Private Sub UserForm_Initialize()

Dim obj As Cls_amount
Dim ctrl As Control

Set CheckCollection = New Collection 'コレクション生成


'spinボタンを作る
Dim newSpin As MSForms.SpinButton

Set mySpin = UserForm1.Controls.Add("Forms.spinbutton.1", "spn_数量")  '名前をつけてSpinボタンを追加
With mySpin
    .Width = 30         '横幅
    .Height = 42        '縦幅
    .Left = 150         '左からの距離
    .Top = 78           '上からの距離
End With


'独自イベントをMe.Collectionに登録する処理
For Each ctrl In Me.Controls
    If TypeName(ctrl) = "SpinButton" Then
        If ctrl.Name = "spn_数量" Then
        
            'スピンアップを登録
            Set obj = New Cls_amount                 'インスタンスの生成
            obj.SetCtrl_SpinButton_数量Up ctrl       'コントロールをセット
            CheckCollection.Add obj                  'コレクションへ追加
            Set obj = Nothing                        'インスタンス破棄
        End If
    End If
Next
    
End Sub

<3 標準モジュール>

Sub 数量UP()

UserForm1.Show

End Sub

<4 クラスモジュール(Cls_amount)>

'独自イベントの宣言
Private WithEvents Target_SpinButton_数量Up As MSForms.SpinButton
'--------------------------------------------------------------------------------------

'Spinボタンに独自イベントをSetする処理
Public Sub SetCtrl_SpinButton_数量Up(new_ctrl_SpinButton_Up As MSForms.SpinButton)
  Set Target_SpinButton_数量Up = new_ctrl_SpinButton_Up
End Sub
'--------------------------------------------------------------------------------------

'SpinUpしたときの処理
Private Sub Target_SpinButton_数量Up_SpinUp()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value + 2

End Sub
'--------------------------------------------------------------------------------------

'SpinDownしたときの処理
Private Sub Target_SpinButton_数量Up_SpinDown()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value - 2

End Sub


以上で実装は完了です。では、解説していきます。

4 処理の解説

ユーザーフォームに独自のイベントを持たせる場合、対象のUserFromに対して独自イベント登録用のCollectionが必要になります。その部分は、<2 ユーザーフォーム コード>の「Private CheckCollection As Collection」です(モジュールレベルに宣言)。

'UserFromのコレクションの宣言(独自イベントの登録用コレクション)
Private CheckCollection As Collection

宣言した「CheckCollection 」に対象のSpinボタンを独自のイベントとして追加します。


次に、独自イベントを記述しているクラスモジュールを作成します。細部を見ていきましょう。

'独自イベントの宣言
Private WithEvents Target_SpinButton_数量Up As MSForms.SpinButton

まず、「Target_SpinButton_数量Up」という独自のイベントを宣言します。

次に、「Target_SpinButton_数量Up」に引数となるSpinボタンを登録する処理を記述します。

'Spinボタンに独自イベントをSetする処理
Public Sub SetCtrl_SpinButton_数量Up(new_ctrl_SpinButton_Up As MSForms.SpinButton)
  Set Target_SpinButton_数量Up = new_ctrl_SpinButton_Up
End Sub

この処理で、「Target_SpinButton_数量Up」に対して、引数となったSpinボタンを独自イベントにSetします(UserFrom1のCheckCollectionへの登録は、フォームモジュール部で説明します)。


次に、独自のイベント処理を記述します。今回のお題のSpinup、Spindown時に±2するイベントです。

'SpinUpしたときの処理
Private Sub Target_SpinButton_数量Up_SpinUp()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value + 2

End Sub
'--------------------------------------------------------------------------------------

'SpinDownしたときの処理
Private Sub Target_SpinButton_数量Up_SpinDown()

UserForm1.Controls("txt_数量").Object.Value = UserForm1.Controls("txt_数量").Object.Value - 2

End Sub


これで、クラスモジュールは完成しました!次にフォームモジュール(UserForm_Initialize)を見ていきましょう。

まず、クラスモジュール(Cls_amount)として「obj」を宣言。また、Controlとして「ctrl」を宣言します。

Dim obj As Cls_amount
Dim ctrl As Control


次に、CheckCollection(独自イベントの登録用コレクション)を実体化します。これで、Me(UserFrom1)に「CheckCollection」というCollectionが実体化され、独自イベントを登録する器ができました。

Set CheckCollection = New Collection 'コレクション生成


次に、Spinボタンを作成するコードを記述します。

'spinボタンを作る
Dim newSpin As MSForms.SpinButton

Set mySpin = UserForm1.Controls.Add("Forms.spinbutton.1", "spn_数量")  '名前をつけてSpinボタンを追加
With mySpin
    .Width = 30         '横幅
    .Height = 42        '縦幅
    .Left = 150         '左からの距離
    .Top = 78           '上からの距離
End With


最後に、一番肝心な「独自イベントをMe.Collectionに登録する処理」です。

'独自イベントをMe.Collectionに登録する処理
For Each ctrl In Me.Controls
    If TypeName(ctrl) = "SpinButton" Then
        If ctrl.Name = "spn_数量" Then
        
            'スピンアップを登録
            Set obj = New Cls_amount                 'インスタンスの生成
            obj.SetCtrl_SpinButton_数量Up ctrl       'コントロールをセット
            CheckCollection.Add obj                  'コレクションへ追加
            Set obj = Nothing                        'インスタンス破棄
        End If
    End If
Next
    
End Sub

Me(UserFrom1)のすべてのコントロール(Me.Controls)内をループ処理します。
コントロールが「SpinButton」かつ、コントロールの名前が「spn_数量」のとき、独自イベント登録処理を実施します。
まず、objを「Cls_amount」として実体化します。
次に、クラスモジュールの「SetCtrl_SpinButton_数量Up」で、Spinボタン(spn_数量)を、WithEventsで宣言した「Target_SpinButton_数量Up」にSetします。
次に、Me(UserFrom1)のCheckCollection(独自イベントの登録用コレクション)に加えます。その後、objを破棄します。


これが、ユーザーフォーム内の処理です。


最後に、標準モジュールにUserFrom1を呼び出す処理を記述します。

Sub 数量UP()

UserForm1.Show

End Sub


これで、最初の動画の通り独自イベントが追加されたSpinボタンが作成され、Spinup、Spindownで±2が可能となりました。



ちなみに、ローカルウィンドウを確認すると以下の画像蛍光線部に独自イベントが登録されていることが確認できます。
f:id:bimori466:20201114232113p:plain


以上で解説終了です。

5 感想

いかがでしょうか。複雑なようですが、要はクラスモジュールで宣言したWithEventsに該当のSpinボタンをセットして、そのSetされたSpinボタンをMe(UserFrom1)のCollectionに追加してあげればいいということです。
私自身、まだあやふやな部分はありますが自分の思考のまとめとして記述しました。とりあえず、こう書けば動きますw。
処理を共通化すると、コードが軽くなります。例えば、Spinボタンが300個あったら、300個1つ1つに、Spinup、Spindownイベントを記述するのは非合理的ですよね。メモリが小さいPCでは、メモリ不足となります。そう言った点でも大事です。

クラスモジュールについて、ネット検索してもあまり参考になるものがなかったので具体的にやりたいことのコードを書いたつもりです。独自イベントの設定方法の理解の助けになれば幸いです。

6 使ってみたい方はnoteで無料DL

実際に使ってみたい方は、noteより無料ダウンロード可能です。
note.com