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 ・・・新着記事一覧を見る

import文(パッケージ・モジュールのインポート)|Python入門(9月24日)
例外処理(try文)とexception一覧|Python入門(9月23日)
リスト内包表記|Python入門(9月22日)
Pythonの引数は参照渡しだが・・・|Python入門(9月21日)
lambda(ラムダ式、無名関数)と三項演算子|Python入門(9月20日)
関数内関数(関数のネスト)とスコープ|Python入門(9月18日)
関数の定義(def文)と引数|Python入門(9月18日)
組み込み関数一覧|Python入門(9月17日)
辞書(dict型)|Python入門(9月16日)
入力規則への貼り付けを禁止する|VBA技術解説(9月16日)


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

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.マクロって何?VBAって何?|VBA入門
5.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
6.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
7.繰り返し処理(For Next)|VBA入門
8.セルに文字を入れるとは(Range,Value)|VBA入門
9.とにかく書いてみよう(Sub,End Sub)|VBA入門
10.マクロはどこに書くの(VBEの起動)|VBA入門




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


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



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