2012-10-18 45 views
18

Conosco tutti i motivi per cui è una cattiva idea. Non mi piace se un'applicazione blocca l'input focus, ma questo è per uso puramente personale e voglio che accada; non disturberà nulla.Come portare la mia domanda in primo piano?

(per i curiosi: eseguo test delle unità in NetBeans, che generano un file di registro. Quando la mia applicazione in background vede la modifica del timestamp del file di log, voglio che analizzi il file di log e venga in primo piano per mostrare i risultati).

This question non ha aiutato, né googling. Sembra che BringToFront() non abbia funzionato per molto tempo e non riesco a trovare nessuna alternativa.

Qualche idea?

+1

Non è possibile farlo. Windows XP aveva una soluzione alternativa che lo avrebbe consentito; versioni da allora lo proibiscono. –

+0

+1 @ken Se sei sicuro al 100%, inserisci una risposta e ti assegnerò. Speravo in qualche trucco oscuro come restringere il vassoio del sistema e poi ripristinarlo, o nasconderlo e poi mostrarlo di nuovo ... – Mawg

+1

Fatto - funzionerà? :-) –

risposta

16

Non è possibile farlo in modo affidabile. Windows XP aveva una soluzione che lo avrebbe consentito, ma da allora le versioni lo proibiscono per la maggior parte (vedi nota sotto). Questo è espressamente indicato nella sezione Osservazioni della documentazione MSDN su SetForegroundWindow:

Il sistema limita quali processi possono impostare la finestra in primo piano. Un processo può impostare la finestra in primo piano solo se si verifica una delle seguenti condizioni:

  • Il processo è il processo in primo piano.
  • Il processo è stato avviato dal processo in primo piano.
  • Il processo ha ricevuto l'ultimo evento di input.
  • Non c'è un processo in primo piano.
  • Il processo in primo piano è in fase di debug.
  • Il foreground non è bloccato (vedere LockSetForegroundWindow).
  • Il timeout del blocco in primo piano è scaduto (vedere SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • Nessun menu attivo.

Un'applicazione non può forzare una finestra in primo piano mentre l'utente sta lavorando con un'altra finestra. Invece, Windows lampeggia il pulsante della barra delle applicazioni della finestra per avvisare l'utente.

Nota l'ultimo paragrafo della documentazione citata, in particolare la prima frase.

Il problema con

questo è per uso esclusivamente personale e voglio che accada; non disturberà nulla.

è che qualsiasi applicazione potrebbe provare a fare la stessa cosa. In che modo "l'uso puramente personale" dice che sei tu personalmente e non solo qualsiasi applicazione? :-)

Nota: ho provato tutto quello che posso pensare per visualizzare la documentazione dell'IDE in primo piano quando faccio clic sul pulsante di aiuto, ma tutto quello che riesco a ottenere è il pulsante della barra delle applicazioni lampeggiante (e io come l'utente vuole che lo faccia).

+0

+1 (e per il tuo commento sopra ;-) Ovviamente, vivrò nella speranza e lascerò aperto per alcune ore prima dell'assegnazione. Come ho detto, speravo in qualche trucco oscuro come il restringimento del vassoio di sistema e poi il ripristino, o il nascondiglio e poi il mostrare di nuovo - ma niente di quello che ho provato funziona :-(È molto lavoro, giusto per evitare Alt-Tab (hmm, forse se avessi un'app "launcher", che poi ha lanciato un'app "process". La nuova app verrà quindi lanciata in primo piano?) – Mawg

+0

Puoi usare lo stile AlwaysOnTop, non che sia amichevole con altre app, ma potrebbe disegnare usaer attenzione, anche se forse alcuni servizi di avviso speciali come Growl/Snarl sono migliori. –

+0

@Ken, grazie, ora è abbastanza buono. Ho rimosso il mio commento e +1 –

3

È possibile scrivere un eseguibile per risolvere questa limitazione.Prendiamo ad esempio una semplice applicazione (non visiva) (fondamentalmente un'app console ma senza la {$ APPTYPE CONSOLE}) con l'unico scopo di portare la finestra desiderata in primo piano.

L'applicazione di monitoraggio in background richiama l'app helper tramite la chiamata della riga di comando (ad esempio ShellExecute) ogni volta che è necessaria l'azione bringtofront. Poiché questa app sta diventando il processo in primo piano, è quindi in grado di portare altre finestre in primo piano (SetForeGroundWindow). È possibile utilizzare FindWindow per ottenere un handle sulla finestra di destinazione o passare i parametri appropriati all'avvio dell'app helper.

+0

+1 @erik Sì, stavo pensando di farlo. è leggermente più impegnativo/un po 'disordinato, ma se è l'unico modo ... – Mawg

12

sto facendo qualcosa di simile in una delle mie applicazioni e questa funzione funziona per me in XP/Vista/W7:

function ForceForegroundWindow(hwnd: THandle): Boolean; 
const 
    SPI_GETFOREGROUNDLOCKTIMEOUT = $2000; 
    SPI_SETFOREGROUNDLOCKTIMEOUT = $2001; 
var 
    ForegroundThreadID: DWORD; 
    ThisThreadID: DWORD; 
    timeout: DWORD; 
begin 
    if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE); 

    if GetForegroundWindow = hwnd then Result := True 
    else 
    begin 
    // Windows 98/2000 doesn't want to foreground a window when some other 
    // window has keyboard focus 

    if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or 
     ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and 
     ((Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and 
     (Win32MinorVersion > 0)))) then 
    begin 
     Result := False; 
     ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow, nil); 
     ThisThreadID := GetWindowThreadPRocessId(hwnd, nil); 
     if AttachThreadInput(ThisThreadID, ForegroundThreadID, True) then 
     begin 
     BringWindowToTop(hwnd); // IE 5.5 related hack 
     SetForegroundWindow(hwnd); 
     AttachThreadInput(ThisThreadID, ForegroundThreadID, False); 
     Result := (GetForegroundWindow = hwnd); 
     end; 
     if not Result then 
     begin 
     // Code by Daniel P. Stasinski 
     SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0); 
     SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0), 
      SPIF_SENDCHANGE); 
     BringWindowToTop(hwnd); // IE 5.5 related hack 
     SetForegroundWindow(hWnd); 
     SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE); 
     end; 
    end 
    else 
    begin 
     BringWindowToTop(hwnd); // IE 5.5 related hack 
     SetForegroundWindow(hwnd); 
    end; 

    Result := (GetForegroundWindow = hwnd); 
    end; 
end; 

Un'altra soluzione non è quella di rubare messa a fuoco e appena messo più in alto della finestra nella z buffer:

procedure ForceForegroundNoActivate(hWnd : THandle); 

begin 
if IsIconic(Application.Handle) then 
    ShowWindow(Application.Handle, SW_SHOWNOACTIVATE); 
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE); 
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE); 
end; 
+0

Funziona * sempre * –

+1

Questo non funziona su Win7 in esecuzione come non amministratore, né funziona correttamente su una macchina in esecuzione su un dominio Win2008, quindi non lo fa 't * always * work, ecco perché ho dato la risposta che ho fatto. :-) Certo, cosa ne so io (e gli autori del sistema operativo stesso)? –

+0

Questo, e approcci simili, non ha mai funzionato per me quando la mia app non era attiva. –

29

Ecco qualcosa di semplice che sembra funzionare, testato con più caselle, comprensivi di XP, Server2003, Vista, Server2008, W7. L'applicazione di prova ha funzionato con un account standard (o amministratore), ha rubato il focus di input dal blocco note durante la scrittura in primo piano.

var 
    Input: TInput; 
begin 
    ZeroMemory(@Input, SizeOf(Input)); 
    SendInput(1, Input, SizeOf(Input)); // don't send anyting actually to another app.. 
    SetForegroundWindow(Handle); 

È possibile modificarlo ulteriormente f.i. per un'app minimizzata o simile se richiesto.

+0

Perché dovrebbe rubare la messa a fuoco? –

+1

@DavidHeffernan, perché "Il processo ha ricevuto l'ultimo evento di input". L'ho provato e funziona molto bene. – kobik

+1

Grazie! Funziona anche in Windows 8.1. –

-1

Form.bringtofront; ?

Dovrebbe funzionare. Se lo metti in un timer rimarrà in primo piano.

3

Questo dovrebbe funzionare anche nel sistema operativo Windows7 + 8. Unico requisito è che un'applicazione stessa possa chiamare funzioni. È più difficile usare un'app esterna per impostare il frontalino di un altro processo.

Application.Restore; // unminimize window, makes no harm always call it 
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE); 
SetWindowPos(self.Handle, HWND_TOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE); 
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE); 

Edit Ok ho scoperto un problema con questo. L'applicazione viene portata in primo piano ma la messa a fuoco viene mantenuta in un'applicazione originale. Usa questa risposta per risolvere il problema, il suo metodo abbastanza complesso ma il copypaste fa il trucco. Prima di chiamare ForceForegroundWindow (wnd) potresti dover chiamare Application.Restore per annullare la finestra. https://stackoverflow.com/a/5885318/185565

3
function WinActivate(const AWinTitle: string): boolean; 
var 
    _WindowHandle: HWND; 
begin 
    Result := false; 
    _WindowHandle := FindWindow(nil, PWideChar(AWinTitle)); 
    if _WindowHandle <> 0 then 
    begin 
    if IsIconic(_WindowHandle) then 
     Result := ShowWindow(_WindowHandle, SW_RESTORE) 
    else 
     Result := SetForegroundWindow(_WindowHandle); 
    end; 
end; 

if WinActivate(self.Caption) then 
    ShowMessage('This works for me in Windows 10'); 
2

Supponendo che non vi siano altre applicazioni in esecuzione StayOnTop è possibile impostare temporaneamente i moduli FormStyle essere fsStayOnTop e poi fare e ripristino delle applicazioni e BringToFront e quindi modificare il FormStyle di nuovo a qualunque cosa fosse.

tmpFormStyle := Application.MainForm.FormStyle; 
Application.MainForm.FormStyle := fsStayOnTop; 
Application.Restore; // optional 
Application.BringToFront; 
Application.MainForm.FormStyle := tmpFormStyle; 

Ancora, questo funziona solo se non ci sono altre applicazioni Stayontop.

Problemi correlati