Credo che questo non è previsto in Excel direttamente, in modo da utilizzare l'API di Windows. Puoi programmare Win32 in VBA!
Spiegazione
È possibile utilizzare la funzione API Win32 SetWinEventHook per arrivare a Windows di segnalare determinati eventi a voi. Compreso EVENT_SYSTEM_FOREGROUND che viene attivato quando cambia la finestra in primo piano. Nell'esempio seguente, controllo l'ID del processo della nuova finestra in primo piano rispetto all'ID processo di Excel. Questo è un modo semplice per farlo, ma rileverà altre finestre di Excel come la finestra VBA allo stesso modo della finestra principale di Excel. Questo può o non può essere il comportamento che si desidera e può essere modificato di conseguenza.
È necessario fare attenzione utilizzando SetWinEventHook, poiché si passa a una funzione di richiamata. Sei limitato a ciò che puoi fare in questa funzione di callback, esiste al di fuori della normale esecuzione di VBA e qualsiasi errore al suo interno causerà l'arresto anomalo di Excel in modo irrecuperabile.
Ecco perché utilizzo Application.OnTime per segnalare gli eventi. Non sono autorizzati a verificarsi in ordine se più eventi vengono attivati più rapidamente rispetto all'aggiornamento di Excel e VBA. Ma è più sicuro. È anche possibile aggiornare una raccolta o una serie di eventi, quindi leggerli di nuovo separatamente dal callback di WinEventFunc.
Esempio di codice
Per verificare ciò, creare un nuovo modulo e incollare questo codice in esso. Quindi eseguire StartHook. Ricordarsi di eseguire StopAllEventHooks prima di chiudere Excel o modificare il codice !! Nel codice di produzione probabilmente aggiungerai StartEventHook e StopAllEventHooks agli eventi WorkBook_Open e WorkBook_BeforeClose per assicurarti che vengano eseguiti nei momenti appropriati. Ricorda, se qualcosa accade con il codice VBA WinEventFunc prima che il blocco si blocchi Excel si bloccherà. Ciò include il codice in fase di modifica o la cartella di lavoro in cui si trova chiuso. Anche fare non premere il pulsante di arresto in VBA mentre un gancio è attivo. Il pulsante stop può cancellare lo stato attuale del programma!
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
È possibile utilizzare un evento a livello di applicazione per eseguire questa operazione. Vedi [Pearson] (http://www.cpearson.com/excel/appevent.aspx). L'uso di 'WorkbookActivate' contrassegna quando una cartella di lavoro in quell'istanza viene attivata. Se si utilizza questo codice in un addin, funzionerà in qualsiasi istanza (ma verrà contrassegnato anche quando si passa da una cartella all'altra all'interno di tale istanza). – brettdj
E anche cosa dovrebbe accadere se viene attivata un'applicazione Excel vuota? non ci sono cartelle di lavoro aperte? Cosa stai cercando di ottenere esattamente? –
@brettdj OK, grazie. Avevo già provato l'evento WorkbookActivate in ThisWorkBook e pensavo che sarebbe stato lo stesso della versione a livello di applicazione che suggerisci. Ho appena provato il tuo suggerimento ma ho ottenuto lo stesso risultato: l'evento Application WorkbookActivate non ha sparato neanche. L'ho messo in un modulo di classe e ho verificato che altri eventi dell'applicazione funzionavano correttamente, quindi sembra che non faccia quello che voglio. –