Wierzę, że to nie jest przewidziane w programie Excel bezpośrednio, więc korzystać z interfejsu API systemu Windows. Możesz zrobić programowanie win32 w VBA!
Wyjaśnienie
Można użyć funkcji API win32 SetWinEventHook aby system Windows zgłosić pewne zdarzenia do ciebie. W tym EVENT_SYSTEM_FOREGROUND, który jest wyzwalany, gdy zmienia się okno pierwszego planu. W poniższym przykładzie sprawdzam identyfikator procesu nowego okna przed identyfikatorem procesu Excela. Jest to prosty sposób, aby to zrobić, ale wykryje inne okna Excela, takie jak okno VBA, tak samo jak główne okno Excela. To może być lub może nie być zachowanie, które chcesz i może być odpowiednio zmienione.
Musisz zachować ostrożność używając SetWinEventHook, ponieważ przekazujesz do niego funkcję zwrotną. Ogranicza się to, co można zrobić w tej funkcji oddzwaniania, istnieje poza normalnym wykonaniem VBA, a wszelkie błędy w nim zawarte spowodują awarię programu Excel w nieporządek i nie do odzyskania.
Dlatego używam Application.OnTime do zgłaszania zdarzeń. Nie występują one w kolejności, gdy wiele zdarzeń jest uruchamianych szybciej niż aktualizacja Excel i VBA. Ale jest bezpieczniej. Można również zaktualizować kolekcję lub tablicę zdarzeń, a następnie odczytać je osobno poza wywołaniem zwrotnym WinEventFunc.
Przykład kodu
Aby to przetestować, tworzenia nowego modułu i przenieść ten kod do niego. Następnie uruchom StartHook. Pamiętaj, aby uruchamiać StopAllEventHooks przed zamknięciem programu Excel lub zmodyfikowaniem kodu !! W kodzie produkcyjnym prawdopodobnie dodasz StartEventHook i StopAllEventHooks do zdarzeń WorkBook_Open i WorkBook_BeforeClose, aby upewnić się, że działają w odpowiednim czasie. Pamiętaj, jeśli coś stanie się z kodem VBA WinEventFunc przed zatrzymaniem haka Program Excel zawiedzie się. Obejmuje to modyfikowany kod lub skoroszyt, w którym jest przechowywany. Również nie naciśnij przycisk zatrzymania w VBA, gdy hak jest aktywny. Przycisk zatrzymania może wyczyścić bieżący stan programu!
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
Do tego celu można użyć zdarzenia na poziomie aplikacji. Zobacz [Pearson] (http://www.cpearson.com/excel/appevent.aspx). Użycie "WorkbookActivate" będzie oznaczało, gdy aktywny jest dowolny skoroszyt w tym wystąpieniu. Jeśli użyjesz tego kodu w dodatku, będzie działał w dowolnej instancji (ale także będzie oznaczał, kiedy karta pomiędzy skoroszytami w tej instancji). – brettdj
A także, co powinno się stać, gdy aktywowana zostanie pusta aplikacja Excel? Czy nie ma otwartych skoroszytów? Co dokładnie próbujesz osiągnąć? –
@brettdj OK, dzięki. Wypróbowałem już wydarzenie WorkbookActivate w ThisWorkBook i pomyślałem, że będzie to to samo, co sugerowana wersja poziomu aplikacji. Po prostu wypróbowałem twoją sugestię, ale otrzymałem ten sam wynik: zdarzenie Application WorkbookActivate również się nie uruchomiło. Wrzuciłem go do modułu klasy i sprawdziłem, czy inne zdarzenia aplikacji działają poprawnie, więc wygląda na to, że nie robi to, co chcę. –