クラスを使った全ブック(他ブック)のイベント補足
VBAでイベントを使う場合は、通常はイベントが発生するオブジェクト(ブックやシート等)のモジュールに記載します、
つまり、各ブックの中にマクロを入れなければなりません。
WithEventsキーワードを付けた変数宣言を使います、
クラスを使って全ブックまたは他ブックのイベントを補足する方法について具体的なVBAコードで紹介します。
ThisWorkbookにWithEventsキーワードを付けた変数宣言をする方法で可能です。
ですが、こまような処理の場合にはクラスを使ったほうが保守や拡張がしやすくなると思います。
今回の場合は、開いている全ブックのイベントを補足したいので、
Applicationのイベントの中にあるブックやシートのイベントを使用します。
これについての詳細は後述します。
>WithEventsキーワード
>Dim ステートメント
Private ステートメント
Public ステートメント
オブジェクトのモジュールのみで使えます、つまり、標準モジュールでは使用できません。
WithEventsは任意の数の変数に宣言できます。
ただし、WithEventsでは配列は作成できません。
また、キーワードNewとWithEventsは一緒には使用できません。
↓
Private WithEvents xlApp As Excel.Application
・・・
Set xlApp = New Excel.Application
このように、WithEventsとNewは分けて使わなければなりません。
>全体の機能と構成
>指定のExcelアプリケーション(既定は同一Excelアプリケーション)内での、
全てのブック・シートのイベントを補足し、
何らかの処理(ここではメッセージボックスを表示して補足できている事のみ確認)を行えるようにしています。
何も指定しない場合は、全てのブック・シートが対象になります。
クラスを起動する標準モジュールのプロシージャーで使用しています。
B列~:シート名を指定、横に何個でも指定可能
シート名が指定されている場合は、指定ブックの指定シートのイベントに対して有効
上図であれば、以下が対象となります。
・Book*のSheet2,Sheet3のシートのイベント
・全てのブックのSheet5*のシートのイベント
Public Sub StartEventClass()
Sub checkBookSheets()
この標準モジュールは、あくまでクラスの動作確認用で作成したものです。
>VBAコード
>
Option Explicit
'対象のExcelアプリケーション
Private WithEvents xlApp As Excel.Application
'対象ブック・シート:1次元配列の要素に構造体を入れる
Private Type typeBookSheets
Book As String 'ブック
Sheets() As String 'シート1,シート2,…
End Type
Private pBookSheets() As typeBookSheets
Private pCntBS As Integer
'イベント停止(一時的に停止させる)
Private pStopEvent As Boolean
'==================================================
' 公開プロパティ
'==================================================
'Excelアプリケーションの設定・取得
Public Property Set ExcelApplication(argApp As Excel.Application)
Set xlApp = argApp
End Property
Public Property Get ExcelApplication() As Excel.Application
Set ExcelApplication = xlApp
End Property
'イベント停止(一時的に停止させる)の取得設定
Public Property Let StopEvent(argStop As Boolean)
pStopEvent = argStop
End Property
Public Property Get StopEvent() As Boolean
StopEvent = pStopEvent
End Property
'==================================================
' 公開メソッド
'==================================================
'対象ブック・シートの初期化
Public Sub InitializeBookSheets()
pCntBS = 0
Erase pBookSheets
End Sub
'対象ブック・シートの設定
Public Function AddBookSheet(ByRef argAry) As Boolean
Dim i1 As Long
Dim i2 As Long
Dim ix As Integer
Dim myArray() As String
'配列の次元数により分岐
Select Case GetDimension(argAry)
Case 1 '1次元配列
ReDim Preserve pBookSheets(pCntBS)
pBookSheets(pCntBS).Book = argAry(LBound(argAry))
ix = 0
ReDim myArray(ix)
For i1 = LBound(argAry) + 1 To UBound(argAry)
If argAry(i1) <> "" Then
ReDim Preserve myArray(ix)
myArray(ix) = argAry(i1)
ix = ix + 1
End If
Next
pBookSheets(pCntBS).Sheets = myArray
Erase myArray
pCntBS = pCntBS + 1
Case 2 '2次元配列
For i1 = LBound(argAry, 1) To UBound(argAry, 1)
ReDim Preserve pBookSheets(pCntBS)
pBookSheets(pCntBS).Book = argAry(i1, LBound(argAry, 2))
ix = 0
ReDim myArray(ix)
For i2 = LBound(argAry, 2) + 1 To UBound(argAry, 2)
If argAry(i1, i2) <> "" Then
ReDim Preserve myArray(ix)
myArray(ix) = argAry(i1, i2)
ix = ix + 1
End If
Next
pBookSheets(pCntBS).Sheets = myArray
Erase myArray
pCntBS = pCntBS + 1
Next
Case Else '1,2次元以外はエラーで戻す
AddBookSheet = False
Exit Function
End Select
AddBookSheet = True
End Function
'対象ブック・シートの全取得:2次元配列で戻す
Public Function GetBookSheets() As Variant
Dim i1 As Integer, i2 As Integer
Dim intMax As Integer
Dim myArray() As String
'配列内の最大シート数を取得
intMax = 0
For i1 = 0 To UBound(pBookSheets)
If UBound(pBookSheets(i1).Sheets) > intMax Then
intMax = UBound(pBookSheets(i1).Sheets)
End If
Next
'構造体の1次元配列を、構造体をバラして2次元配列に
ReDim myArray(UBound(pBookSheets), intMax + 1)
For i1 = 0 To UBound(pBookSheets)
myArray(i1, 0) = pBookSheets(i1).Book
For i2 = LBound(pBookSheets(i1).Sheets) To UBound(pBookSheets(i1).Sheets)
myArray(i1, i2 + 1) = pBookSheets(i1).Sheets(i2)
Next
Next
GetBookSheets = myArray
End Function
'==================================================
' クラスのメソッド
'==================================================
'クラスの初期化
Private Sub Class_Initialize()
Set Me.ExcelApplication = Application
Me.StopEvent = False
Me.InitializeBookSheets
End Sub
'クラスの終了処理
Private Sub Class_Terminate()
Set xlApp = Nothing
End Sub
'==================================================
' Applicationのブックイベント
'==================================================
'ブックが開かれたときに発生
Private Sub xlApp_WorkbookOpen(ByVal wb As Workbook)
If Me.StopEvent Then Exit Sub
If Not CheckBook(wb) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "WorkbookOpen : " & wb.FullName
End Sub
'ブックが閉じられる直前に発生
Private Sub xlApp_WorkbookBeforeClose(ByVal wb As Workbook, Cancel As Boolean)
If Me.StopEvent Then Exit Sub
If Not CheckBook(wb) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "WorkbookBeforeClose : " & wb.FullName
End Sub
'新しいブックが作成されたときに発生
Private Sub xlApp_NewWorkbook(ByVal wb As Workbook)
If Me.StopEvent Then Exit Sub
If Not CheckBook(wb) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "NewWorkbook : " & wb.Name
End Sub
'==================================================
' Applicationのシートイベント
'==================================================
'シートがアクティブになったときに発生
Private Sub xlApp_SheetActivate(ByVal Sh As Object)
If Me.StopEvent Then Exit Sub
If Not CheckSheet(Sh) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "SheetActivate : [" & Sh.Parent.Name & "]" & Sh.Name
End Sub
'ワークシートのセルが変更されたときに発生
Private Sub xlApp_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Me.StopEvent Then Exit Sub
If Not CheckSheet(Sh) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "SheetChange : " & Target.Address(external:=True)
End Sub
'セルがダブルクリックされたときに発生
Private Sub xlApp_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
If Me.StopEvent Then Exit Sub
If Not CheckSheet(Sh) Then Exit Sub
'メッセージボックスでイベント補足を確認
MsgBox "SheetBeforeDoubleClick : " & Target.Address(external:=True)
End Sub
'==================================================
' 非公開メソッド
'==================================================
'対象ブックの判定
Private Function CheckBook(ByVal wb As Workbook) As Boolean
'指定なしはすべて対象とする
If pCntBS = 0 Then
CheckBook = True
Exit Function
End If
'ブック・シート指定の配列にブック名があるか判定
Dim i1 As Integer
CheckBook = False
For i1 = 0 To UBound(pBookSheets)
'ブックの名称判定
If wb.Name Like pBookSheets(i1).Book Then
'シート指定がない時のみブックの指定と判定
If pBookSheets(i1).Sheets(0) = "" Then
CheckBook = True
Exit Function
End If
End If
Next
End Function
'対象シートの判定
Private Function CheckSheet(ByVal ws As Worksheet) As Boolean
'指定なしはすべて対象とする
If pCntBS = 0 Then
CheckSheet = True
Exit Function
End If
'ブック・シート指定の配列にシート名があるか判定
Dim i1 As Integer, i2 As Integer
Dim wb As Workbook
CheckSheet = False
Set wb = ws.Parent
For i1 = 0 To UBound(pBookSheets)
'ブックの名称判定
If wb.Name Like pBookSheets(i1).Book Then
'シートの名称判定
For i2 = LBound(pBookSheets(i1).Sheets) To UBound(pBookSheets(i1).Sheets)
If ws.Name Like pBookSheets(i1).Sheets(i2) Then
CheckSheet = True
Exit Function
End If
Next
End If
Next
End Function
'配列の次元数取得とエラー値判定:1,2以外の戻り値はエラー
Private Function GetDimension(ByVal argAry) As Integer
On Error Resume Next
'配列の次元数取得
Dim intDim As Integer
Dim tmpDim As Integer
intDim = 0
Do While Err.Number = 0
intDim = intDim + 1
'エラーになった時点で配列が終わり
tmpDim = UBound(argAry, intDim)
Loop
Err.Clear
intDim = intDim - 1
'配列の場合、エラー値データの判定
Dim vTemp
Select Case intDim
Case 1, 2
For Each vTemp In argAry
If IsError(vTemp) Then
GetDimension = 0
Exit Function
End If
Next
End Select
GetDimension = intDim
On Error GoTo 0
End Function
以下のVBAコードの解説で簡単に説明しています。
個々のステートメントについての詳細までは解説していません。
VBA内のコメントを頼りに読み解いてください。
今回のクラス特有の機能部分にはあまりこだわらず、
クラスの全体構成と、他ブックのイベント補足方法について確認しつつ、
実際に動かして、ブレークポイントで止めたりしながら動作確認してみてください。
>VBAコードの解説
>変数
Book As String 'ブック
Sheets() As String 'シート1,シート2,…
End Type
Private pBookSheets() As typeBookSheets
Private pCntBS As Integer
構造体のメンバーはBookとSheets()になります。
Bookはプック名をいれ、
Sheets()は、シート名を強い列で入れます。
そして、構造体typeBookSheetsを型に持つ配列を定義しています。
pCntBSは、配列の現在要素数のカウントに使用します。
そのような場合に、この変数をFalseにすることでその間のイベント発生を停止できるようにしています。
Application.EnableEvents = False
こちらを使っても良いでしょう、この場合はこのクラスだけではなく全てのイベントが抑止されます。
公開プロパティ
Class_Initializeで自身の動作しているExcel.Applicationを入れているので、
通常は設定する必要がありません。
Trueを設定すると、イベント発生しても何も動作しないようにしています。
公開メソッド
1次元配列と2次元配列をサポートしています。
そのため、引数は型をVariantにしています。
Array(・・・)なら1次元配列として、必要な回数このメソッドを呼び出します。
セル範囲なら2次元配列をこのメソッドに渡せば1回で複数の設定を入れることができます。
※標準モジュール参照
対象ブック・シートの設定状態を取得し確認するためのプロパティです。
VBA開発時のデバッグ等で使用する目的で作成しています。
クラスのメソッド
クラス内の変数・プロパティの初期化を行います。
ここでは特にやることもないので、
クラス内で変数に保持しているExcel.Applicationを解放しています。
Applicationのブックイベント
Applicationのシートイベント
非公開メソッド
存在したときにはTrueを返し、存在しないときにはFalseを返します。
構造体のBookが対象ブック名で、Sheets(0)が空文字の場合がブックイベントに対する指定になります。
名称はLike演算子を使って比較しています。
存在したときにはTrueを返します。
構造体のBookが対象ブック名、Sheets()がシート名と一致している場合に対象となります。
名称はLike演算子を使って比較しています。
1次元2次元配列の場合は、エラー値が含まれていないかのチェックも行っています。
標準モジュールでのクラスの使い方
Option Explicit
Private myClass As clsEvent
Public Sub StartEventClass()
'クラスのインスタンス
Set myClass = New clsEvent
'Excel.Applicationを設定(同一Appなら設定不要)
Set myClass.ExcelApplication = Application
'ブック・シートの指定を初期化、不要だが記述説明の意味で
myClass.InitializeBookSheets
'イベント発生停止、不要だが記述説明の意味で
myClass.StopEvent = True
'***** シートから設定する場合 *****
Dim myArray
With ThisWorkbook.Worksheets(1).Range("A1")
If .CurrentRegion.Rows.Count > 1 Then
myArray = Intersect(.CurrentRegion, .CurrentRegion.Offset(1))
'シート入力なのでエラー判定
If Not myClass.AddBookSheet(myArray) Then
MsgBox "シートにエラー値があります。"
Set myClass = Nothing
Exit Sub
End If
End If
End With
'***** 配列を直書きして設定する場合 *****
'ブック,シート1,シート2,…シート省略時はブックイベント
Call myClass.AddBookSheet(Array("Book4"))
Call myClass.AddBookSheet(Array("*", "Sheet7"))
'確認のため設定内容をイミィディエイトに出力
Call checkBookSheets
'イベント発生再開
myClass.StopEvent = False
End Sub
'クラスに指定したブック・シートを配列で受けとる
Sub checkBookSheets()
Dim i1 As Integer
Dim i2 As Integer
Dim sTemp As String
Dim myArray
myArray = myClass.GetBookSheets
For i1 = 0 To UBound(myArray)
sTemp = myArray(i1, 0)
For i2 = 1 To UBound(myArray, 2)
sTemp = sTemp & " , " & myArray(i1, i2)
Next
Debug.Print sTemp
Next
End Sub
Private myClass As clsEvent
モジュールレベル変数として、クラスの変数宣言をしています。
Set myClass = New clsEvent
クラスのインスタンスを作成しています。
モジュールレベル変数宣言時にNewしても構いません。
主な作成目的は、クラス作成時のデバッグ用途になります。
アプリケーションのイベント一覧と調べ方
アブリケーションのイベント一覧
名前 | 説明 |
AfterCalculate | 中断中の更新作業(同期と非同期の両方)と結果の計算作業がすべて完了すると、AfterCalculateイベントが発生します。 |
NewWorkbook | 新しいブックを作成したときに発生します。 |
ProtectedViewWindowActivate | [保護されたビュー]ウィンドウがアクティブになったときに発生します。 |
ProtectedViewWindowBeforeClose | [保護されたビュー]ウィンドウまたは[保護されたビュー]ウィンドウ内のブックを閉じる直前に発生します。 |
ProtectedViewWindowBeforeEdit | 指定した[保護されたビュー]ウィンドウでブックの編集が有効になる直前に発生します。 |
ProtectedViewWindowDeactivate | [保護されたビュー]ウィンドウが非アクティブになったときに発生します。 |
ProtectedViewWindowOpen | ブックを[保護されたビュー]ウィンドウで開いたときに発生します。 |
ProtectedViewWindowResize | [保護されたビュー]ウィンドウのサイズを変更したときに発生します。 |
SheetActivate | シートがアクティブになったときに発生します。 |
SheetBeforeDoubleClick | 既定のダブルクリックの操作の前に、ワークシートをダブルクリックしたときに発生します。 |
SheetBeforeRightClick | 既定の右クリックの操作の前に、ワークシートを右クリックしたときに発生します。 |
SheetCalculate | ワークシートを再計算したり、グラフでデータをプロットして変更した後に発生します。 |
SheetChange | ユーザーまたは外部リンクにより、ワークシートのセルが変更されるときに発生します。 |
SheetDeactivate | シートが非アクティブになったときに発生します。 |
SheetFollowHyperlink | Excelのハイパーリンクをクリックすると発生します。 ワークシートレベルでのイベントについては、FollowHyperlinkイベントのヘルプトピックを参照してください。 |
SheetPivotTableAfterValueChange | ピボットテーブル内のセルまたはセル範囲が編集または再計算された後に発生します(数式を含むセルの場合)。 |
SheetPivotTableBeforeAllocateChanges | ピボットテーブルに変更が適用される前に発生します。 |
SheetPivotTableBeforeCommitChanges | ピボットテーブルのOLAPデータソースに対する変更が適用される前に発生します。 |
SheetPivotTableBeforeDiscardChanges | ピボットテーブルに対する変更が破棄される前に発生します。 |
SheetPivotTableUpdate | ピボットテーブルレポートのシートが更新された後に発生します。 |
SheetSelectionChange | いずれかのワークシートで選択範囲を変更したときに発生します。 選択範囲がグラフシート上にある場合は発生しません。 |
WindowActivate | ブックのウィンドウがアクティブになったときに発生します。 |
WindowDeactivate | ブックのウィンドウが非アクティブになったときに発生します。 |
WindowResize | ブックのウィンドウサイズを変更したときに発生します。 |
WorkbookActivate | ブックがアクティブになったときに発生します。 |
WorkbookAddinInstall | ブックがアドインとして組み込まれたときに発生します。 |
WorkbookAddinUninstall | アドインブックの組み込みを解除したときに発生します。 |
WorkbookAfterSave | ブックが保存された後に発生します。 |
WorkbookAfterXmlExport | MicrosoftOfficeExcelがデータを保存するか、指定されたワークブックからXMLデータをエクスポートした後で発生します。 |
WorkbookAfterXmlImport | 既存のXMLデータ接続が更新されたか、または開いているMicrosoftExcelブックに新しいXMLデータがインポートされた後に発生します。 |
WorkbookBeforeClose | 開いたブックを閉じる直前に発生します。 |
WorkbookBeforePrint | 開いているブックを印刷する前に発生します。 |
WorkbookBeforeSave | 開いているブックを保存する前に発生します。 |
WorkbookBeforeXmlExport | MicrosoftOfficeExcelがデータを保存するか、指定されたワークブックからXMLデータをエクスポートする前に発生します。 |
WorkbookBeforeXmlImport | 既存のXMLデータ接続が更新されるか、または開いているMicrosoftExcelブックに新しいXMLデータがインポートされる前に発生します。 |
WorkbookDeactivate | 開いているブックが非アクティブになったときに発生します。 |
WorkbookNewChart | 開いているブックで新しいグラフが作成されるときに発生します。 |
WorkbookNewSheet | 開いているブックで新しいシートが作成されるときに発生します。 |
WorkbookOpen | ブックを開くときに発生します。 |
WorkbookPivotTableCloseConnection | ピボットテーブルレポート接続が閉じた後に発生します。 |
WorkbookPivotTableOpenConnection | ピボットテーブルレポート接続が開いた後に発生します。 |
WorkbookRowsetComplete | ユーザーがOLAPピボットテーブルで行セットアクションを起動するか、レコードセットを詳細表示するとWorkbookRowsetCompleteイベントが発生します。 |
WorkbookSync | ドキュメントワークスペースに含まれているブックのローカルコピーがサーバー上のコピーと同期されたときに発生します。 |
引数については、以下のイベントの調べ方を参考にして使用するイベントについて調べてください。
アプリケーションのイベントの調べ方
メンバーの中から使用したいイベントを選択、
表示されます。
そして、
↓
Private xlApp_SheetChange(Byval Sh As Object, Target As Range)
先頭にPrivateを書いて、
WithWithEventsキーワードを付けた変数(xlApp)に_(アンダバー)を付けます。
つまり、
WithWithEvents変数_イベント名
このようにします。
そして、wbやshtのオブジェクトにはByvalを付けてください。
これを付けないと、以下のエラーが出てしまいます。
つまり省略のByRefではだめだということです。
最後に
・WithEventsの使い方
同じテーマ「VBAクラス入門」の記事
VBAクラス入門:クラスとは?オブジェクト指向とは?
クラスを使った全ブック(他ブック)のイベント補足
VBAクラスの作り方:列名の入力支援と列移動対応
VBAクラスの作り方:列名のプロパティを自動作成する
VBAクラスの作り方:独自Rangeっぽいものを作ってみた
クラスとイベントとマルチプロセス並列処理
クラスとCallByNameとポリモーフィズム(多態性)
オートフィルターを退避回復するVBAクラス
オートフィルター退避回復クラスを複数シート対応させるVBAクラス
コレクション(Collection)の並べ替え(Sort)に対応するクラス
VBAクラスのAttributeについて(既定メンバーとFor Each)
新着記事NEW ・・・新着記事一覧を見る
TRIMRANGE関数(セル範囲をトリム:端の空白セルを除外)|エクセル入門(2024-08-30)
正規表現関数(REGEXTEST,REGEXREPLACE,REGEXEXTRACT)|エクセル入門(2024-07-02)
エクセルが起動しない、Excelが立ち上がらない|エクセル雑感(2024-04-11)
ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.繰り返し処理(For Next)|VBA入門
3.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
4.変数宣言のDimとデータ型|VBA入門
5.RangeとCellsの使い方|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.条件分岐(Select Case)|VBA入門
10.ブック・シートの選択(Select,Activate)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。