2013-12-10 6 views
6

Excel内のウィンドウを切り替えると、さまざまなレベルでWindowActivateイベントが発生しますが、Excelが実行されるとイベントを発生させる方法がありますフォアグラウンドアプリケーション?たとえば、ブラウザでしばらくしてからExcelをクリックしてExcelのウィンドウに戻ると、何のイベントも発生しません。これを検出する方法はありますか?Excelインスタンスを含むウィンドウがアクティブになったときの検出(0120)VBAで

ハイパーテキスト機能に基づいてマウスオーバー機能がチャートをアクティブにする機能を失うことがあるため、VBAアプリケーションの一部の要素をリフレッシュしたいと思います。私は、ワークシートの保護を解除して保護するか、オブジェクトの一部を破棄して再初期化することで修正できます。私が探しているイベントでこの行動を誘発したいと思います。

私はSendKeysでこれを行うこともできますが、SendKeysの文書化されたバグのためにキーボードの設定(例えばスクロールロック)が消去され、私が望む以上に画面がちらつきます。

コードはVBAに常駐するため、特定のブックへの操作が制限されます。 Excelインスタンスウィンドウの入力時に別の(パッシブ)ブックがアクティブな場合、アクションは実行されず、ユーザーがブックを含むブックを選択すると、アプリケーションを更新するためにWorkbookActivateイベントを使用できます。ここで

+0

これを行うには、アプリケーションレベルのイベントを使用できます。 [Pearson](http://www.cpearson.com/excel/appevent.aspx)を参照してください。 'WorkbookActivate'を使用すると、そのインスタンスのブックがアクティブになったときにフラグが立てられます。このコードをアドインで使用すると、どのインスタンスでも動作します(ただし、そのインスタンス内のブック間でタブするとフラグが立てられます)。 – brettdj

+0

また、空のExcelアプリケーションがアクティブになった場合にはどうなりますか?つまり、開いているブックはありませんか?あなたは正確に何を達成しようとしていますか? –

+0

@brettdjありがとう、ありがとう。私はすでにThisWorkBookでWorkbookActivateイベントを試していましたが、あなたが提案するアプリケーションレベルのバージョンと同じであると思いました。私はあなたの提案を試みましたが、同じ結果を得ました:Application WorkbookActivateイベントは起動しませんでした。私はそれをクラスモジュールに入れて、他のアプリケーションイベントが正常に動作していることを確認しました。それは、私が望んでいないように見えます。 –

答えて

2

私はこれを直接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