VBA技術解説
VBAクラスを使ったイベント作成(Event,RaiseEvent,WithEvents)

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
最終更新日:2020-01-06

VBAクラスを使ったイベント作成(Event,RaiseEvent,WithEvents)


VBAクラスを使う事で、ユーザー定義イベントを作成したり、動的にイベントを割り当てる事が出来ます。
ユーザー独自のイベントを作成したり、フォームに動的に追加したコントロールにイベントを設定することができます。


EventステートメントとRaiseEventステートメントを使う事で、ユーザー定義イベントつまりユーザー独自のイベントを作成できます。
変数宣言にWithEventsキーワードを指定することで、クラスで発生するイベントに応答することができます。

ここでは、ユーザーフォームを使って、極めて単純なイベントを実装しています。
このVBAサンプルは、これで何かができるというものではなく、
クラスのイベントを理解する為に極めて単純化したVBAコードになります。

Eventステートメント

ユーザー定義イベントを宣言します。
[Public] Event プロシージャー名[(引数リスト)]

引数リストは、プロシージャーの引数リストと同様ですが、
イベントに名前付き引数、省略可能な引数、またはParamArray引数を指定することはできません。

モジュールレベルで宣言します。
値を返すようにイベントを宣言することはできません。
イベントが宣言されたら、 RaiseEventステートメントを使用してイベントを発生させます。
イベントは、それが宣言されているモジュール内でしか生成できません。

RaiseEventステートメント

モジュールレベルで宣言したイベントを発生させます。
RaiseEvent イベント名[(引数リスト)]

イベント名は、モジュール内でEventステートメントで宣言されたイベントの名前です。
イベントが発生したモジュール内で、そのイベントが宣言されていない場合は、エラーが発生します。

WithEventsキーワード

WithEventsキーワードは、次の構文で使用します。
Dim ステートメント
Private ステートメント
Public ステートメント
モジュール レベルで使用します。

変数がイベントに対応するためのオブジェクト変数であることを指定するキーワードです。
オブジェクトのモジュールのみで使えます、つまり、標準モジュールでは使用できません。
WithEventsは任意の数の変数に宣言できます。
ただし、WithEventsでは配列は作成できません。
また、キーワードNewとWithEventsは一緒には使用できません。

Private WithEvents xlApp As New Excel.Application

Private WithEvents xlApp As Excel.Application
・・・
Set xlApp = New Excel.Application
このように、WithEventsとNewは分けて使わなければなりません。

標準モジュールと動作概要

ユーザーフォームにボタンが2つだけ存在し、クリックでメッセージボックスを表示します。
たったこれだけですが、
ボタン1とボタン2では全く違った実装となります。

マクロ VBA クラス class event

ボタン1
ユーザーフォームに最初から配置されているボタンです。
クリックすると、3秒後にセッメージボックスが表示されます。

マクロ VBA クラス class event

ボタン2
ユーザーフォームの初期化(Initialize)で動的に追加したボタンです。。
クリックすると、直ぐにセッメージボックスが表示されます。

マクロ VBA クラス class event


起動するプロシージャーは以下になります。

Sub EventTest()
  UserForm1.Show
End Sub

記述場所およびプロシージャー名等、特に何も制限はありません。
UserForm1を表示さえすれば、どのような方法でも構いません。

ユーザーフォーム(UserForm1)

ユーザーフォームのオブジェクト名:UserForm1

マクロ VBA クラス class event

ボタンを1つだけ配置、ボタンのオブジェクト名:btn1

Option Explicit

'ボタン1:イベントに応答するために定義する変数
Private WithEvents mTimer As clsEvent

'ボタン2:動的ボタン対応クラスのインスタンス変数
Private clsEvent As clsEvent

'ボタン1:最初から存在するbtn1のClickイベント
Private Sub btn1_Click()
  Set mTimer = New clsEvent
  Call mTimer.TimerMsg(3)
End Sub

'ボタン1:WithEventsを指定したmTimerのTimerEventイベント
Private Sub mTimer_TimerEvent(ByVal aTime As Long)
  MsgBox aTime & "秒経過しました。"
End Sub

'ボタン2:イベントクラスにボタンを追加
Private Sub UserForm_Initialize()
  Set clsEvent = New clsEvent
  Set clsEvent.Button = addButton(Me.btn1.Top + 50, _
                  Me.btn1.Left, _
                  Me.btn1.Height, _
                  Me.btn1.Width, _
                  "ボタン2")
End Sub

'ボタン2:ユーザーフォームにボタンを追加
Private Function addButton(ByVal aTop As Single, _
              ByVal aLeft As Single, _
              ByVal aHeight As Single, _
              ByVal aWidth As Single, _
              ByVal aName As String) As MSForms.CommandButton
  Set addButton = Me.Controls.Add("Forms.CommandButton.1", aName)
  With addButton
    .Top = aTop
    .Left = aLeft
    .Height = aHeight
    .Width = aWidth
    .Caption = aName
  End With
End Function

クラス(clsEvent)

クラスのオブジェクト名:clsEvent

Option Explicit

'ボタン1:イベントの宣言、RaiseEventでイベント発生
Public Event TimerEvent(ByVal aTime As Long)

'ボタン2:イベントに応答するために定義する変数
Private WithEvents myButton As MSForms.CommandButton

'ボタン1:指定時間後にTimerEventイベントを発生させる
Public Sub TimerMsg(ByVal aTime As Long)
  Application.Wait Now() + TimeSerial(0, 0, aTime)
  RaiseEvent TimerEvent(aTime)
End Sub

'ボタン2:クラスで扱うボタンの設定/取得
Public Property Get Button() As Control
  Set Button = myButton
End Property
Public Property Set Button(ByVal addBtn As Control)
  Set myButton = addBtn
End Property

'ボタン2:クラスで扱うボタンのClickイベント
Private Sub myButton_Click()
  MsgBox myButton.Caption & "がクリックされました。"
End Sub

クラスを使ったイベントの解説

2つのボタンは全く互いに関係はありません、基本的に独立したボタンです。
(ボタン2を配置する時だけボタン1を使っています。)
本来は、
・EventステートメントとRaiseEventステートメントでの、ユーザー定義イベント
・WithEventsキーワードでの、クラス発生イベントの応答
これらを別々に解説するところなのでしょうが、ここではこの2つを一緒にしたものになります。
クラスを使ったイベントとして、混乱しやすく覚えづらい部分なので、その違いを比較しやすいようにと言う目的があります。

VBAの中でのコメントとして、
ボタン1:
ボタン2:
その変数またはプロシージャーが使われているボタンを指しています。
変数およびプロシージャーは、それぞれのボタンで全く別々のものが使用されています。

ボタン1の動作順
ユーザーフォームに最初から配置されているボタンです。
ユーザーフォームが表示された後にボタン1クリック。

btn1_Clickプロシージャー
TimerMsgプロシージャー
RaiseEvent TimerEvent
ここでEventステートメントで定義されているTimerEventを発生させる
mTimer_TimerEventプロシージャー
WithEventsキーワード定義したmTimerのTimerEventが呼ばれる

マクロ VBA クラス class event

ここでの動作自体は、単にClickイベントでメッセージ表示している事と何も変わりません。
あくので、EventとRaiseEventの使い方のサンプルVBAとしての意味合いだけのものです。


ボタン2の動作順
フォームに動的に追加したコントロールにイベントを設定しています。。
ボタン2は、ユーザーフォームには最初は配置されていないボタンです。
ユーザーフォームが初めて表示(使用)されたとき、

UserForm_Initialize
Set clsEvent = New clsEvent 'クラスのインスタンス
Set clsEvent.Button = addButton(… 'クラスにボタンを登録
addButton

ここで動的にボタンを作成し、クラスにボタンを登録しています。
ユーザーフォームが表示された後にボタン2クリック。

myButton_Click
WithEvents myButton As MSForms.CommandButton
フォーム標準のボタンを割り当てています。
Clickはボタンに標準で存在するイベントです。
プロシージャー名は、
変数名_イベント名

マクロ VBA クラス class event

VBAクラスを使ったイベントの最後に

今回紹介した2つの処理
・EventステートメントとRaiseEventステートメントでの、ユーザー定義イベント
・WithEventsキーワードでの、クラス発生イベントの応答
いずれも頻繁に使うものではないと思います。

したがって、全部を覚えようとすることは無いと思います。
動作の仕組みを理解しておき、実際に使う時に調べながら記述できるようにしておくだけで良いでしょう。



同じテーマ「VBAクラス入門」の記事

VBAクラスの作り方:列名のプロパティを自動作成する
VBAクラスの作り方:独自Rangeっぽいものを作ってみた
クラスとイベントとマルチプロセス並列処理
クラスとCallByNameとポリモーフィズム(多態性)
オートフィルタを退避回復するVBAクラス
オートフィルタ退避回復クラスを複数シート対応させるVBAクラス
コレクション(Collection)の並べ替え(Sort)に対応するクラス
VBAクラスのAttributeについて(既定メンバーとFor Each)
VBAクラスを使ったイベント作成(Event,RaiseEvent,WithEvents)
VBAで音楽再生するクラスを作成
図形を方程式で動かすVBAクラス


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

ユーザーに絶対に停止させたくない場合のVBA設定|VBA技術解説(4月1日)
CharactersプロパティとCharactersオブジェクト|VBA技術解説(3月31日)
指数近似/対数近似/累乗近似(掲載順位とCTR)|エクセル関数超技(3月31日)
練習問題32(連続数値部分を取り出し記号で連結)|VBA練習問題(3月24日)
連続数値部分を取り出し記号で連結|エクセル関数超技(3月24日)
数式バーの高さを数式の行数で自動設定|VBAサンプル集(3月21日)
LET関数(数式で変数を使う)|エクセル入門(3月21日)
スピルに対応したXSPLITユーザー定義関数(文字区切り)|VBAサンプル集(3月15日)
XMATCH関数(範囲から値を検索し一致する相対位置)|エクセル入門(3月14日)
XLOOKUP関数(範囲を検索し一致する対応項目を返す)|エクセル入門(3月14日)


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

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
4.マクロって何?VBAって何?|VBA入門
5.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
6.変数宣言のDimとデータ型|VBA入門
7.ひらがな⇔カタカナの変換|エクセル基本操作
8.繰り返し処理(For Next)|VBA入門
9.徹底解説(VLOOKUP,MATCH,INDEX,OFFSET)|エクセル関数超技
10.セルに文字を入れるとは(Range,Value)|VBA入門




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


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



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