私はこれを直接Excelで提供されていないと考えているので、WindowsのAPIを使用します。あなたはVBAでwin32プログラミングをすることができます!
説明
あなたはあなたに特定のイベントをレポートするためにWindowsを取得するために、Win32 API関数SetWinEventHookを使用することができます。フォアグラウンドウィンドウが変更されたときにトリガされるEVENT_SYSTEM_FOREGROUNDを含みます。以下の例では、新しいフォアグラウンドウィンドウのプロセスIDをExcelのプロセスIDと照合します。これは簡単な方法ですが、メインのExcelウィンドウと同じVBAウィンドウなどの他のExcelウィンドウを検出します。これはあなたが望むふるまいである場合とそうでない場合があり、それに応じて変更することができます。
SetWinEventHookは、コールバック関数を渡すので注意が必要です。このコールバック関数では、VBAの通常の実行の範囲外で存在し、その中にエラーがあれば、Excelがひどく回復不能な方法でクラッシュする可能性があります。
私はApplication.OnTimeを使用してイベントを報告しています。複数のイベントがExcelおよびVBAの更新よりも迅速にトリガされた場合、それらは順番に発生することはありません。しかし、それはより安全です。また、イベントのコレクションまたは配列を更新してから、WinEventFuncコールバックの外部でそれらを別々に読み取ることもできます。
サンプルコード
これをテストするには、新しいモジュールを作成し、そこにこのコードを貼り付けます。その後、StartHookを実行します。 Excelを終了したりコードを修正する前にStopAllEventHooksを実行することを忘れないでください!!プロダクションコードでは、おそらくStartEventHookとStopAllEventHooksをWorkBook_OpenイベントとWorkBook_BeforeCloseイベントに追加して、それらが適切なタイミングで実行されるようにします。フックが停止する前にWinEventFunc VBAコードに何かが発生した場合は、Excelがにクラッシュすることを覚えておいてください。これには、変更中のコードまたは閉じられているときに格納されているブックが含まれます。 もありませんフックがアクティブな間にVBAの停止ボタンを押します。停止ボタンは、現在のプログラム状態を消去することができます!
Option Explicit
Private Const EVENT_SYSTEM_FOREGROUND = &H3&
Private Const WINEVENT_OUTOFCONTEXT = 0
Private Declare Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Long, ByVal eventMax As Long, _
ByVal hmodWinEventProc As Long, ByVal pfnWinEventProc As Long, ByVal idProcess As Long, _
ByVal idThread As Long, ByVal dwFlags As Long) As Long
Private Declare Function GetCurrentProcessId Lib "kernel32"() As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private pRunningHandles As Collection
Public Function StartEventHook() As Long
If pRunningHandles Is Nothing Then Set pRunningHandles = New Collection
StartEventHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 0&, AddressOf WinEventFunc, 0, 0, WINEVENT_OUTOFCONTEXT)
pRunningHandles.Add StartEventHook
End Function
Public Sub StopEventHook(lHook As Long)
Dim LRet As Long
If lHook = 0 Then Exit Sub
LRet = UnhookWinEvent(lHook)
End Sub
Public Sub StartHook()
StartEventHook
End Sub
Public Sub StopAllEventHooks()
Dim vHook As Variant, lHook As Long
For Each vHook In pRunningHandles
lHook = vHook
StopEventHook lHook
Next vHook
End Sub
Public Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
ByVal hWnd As Long, ByVal idObject As Long, ByVal idChild As Long, _
ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
'This function is a callback passed to the win32 api
'We CANNOT throw an error or break. Bad things will happen.
On Error Resume Next
Dim thePID As Long
If LEvent = EVENT_SYSTEM_FOREGROUND Then
GetWindowThreadProcessId hWnd, thePID
If thePID = GetCurrentProcessId Then
Application.OnTime Now, "Event_GotFocus"
Else
Application.OnTime Now, "Event_LostFocus"
End If
End If
On Error GoTo 0
End Function
Public Sub Event_GotFocus()
Sheet1.[A1] = "Got Focus"
End Sub
Public Sub Event_LostFocus()
Sheet1.[A1] = "Nope"
End Sub
これを行うには、アプリケーションレベルのイベントを使用できます。 [Pearson](http://www.cpearson.com/excel/appevent.aspx)を参照してください。 'WorkbookActivate'を使用すると、そのインスタンスのブックがアクティブになったときにフラグが立てられます。このコードをアドインで使用すると、どのインスタンスでも動作します(ただし、そのインスタンス内のブック間でタブするとフラグが立てられます)。 – brettdj
また、空のExcelアプリケーションがアクティブになった場合にはどうなりますか?つまり、開いているブックはありませんか?あなたは正確に何を達成しようとしていますか? –
@brettdjありがとう、ありがとう。私はすでにThisWorkBookでWorkbookActivateイベントを試していましたが、あなたが提案するアプリケーションレベルのバージョンと同じであると思いました。私はあなたの提案を試みましたが、同じ結果を得ました:Application WorkbookActivateイベントは起動しませんでした。私はそれをクラスモジュールに入れて、他のアプリケーションイベントが正常に動作していることを確認しました。それは、私が望んでいないように見えます。 –