2010-02-23 4 views
15

Attualmente con swt, a volte voglio che un programma arrivi in ​​modo arbitrario in primo piano (come potrebbe fare una sveglia).Come si forza un programma java swt a "spostarsi in primo piano"?

Tipicamente i seguenti lavori (JRuby):

@shell.setMinimized(false) 
@shell.forceActive 

Questo porta il guscio al fronte se è stato minimizzato.

Creare un nuovo guscio in qualsiasi momento porta anche il (nuovo guscio) in primo piano.

Fin qui tutto bene, tuttavia, se il guscio è non ridotti al minimo, il codice precedente appena lampeggia (lampeggiante) l'icona dell'applicazione nella barra delle applicazioni. Beh, in realtà la prima volta che lo esegui, lo porta in primo piano. Dopodiché, lampeggia semplicemente nella barra delle applicazioni. Quello è Windows. Su Linux sembra solo lampeggiare nella barra delle applicazioni (predefinito di ubuntu).

Qualcuno sa di un modo multipiattaforma di far arrivare l'app in primo piano, in swt?

Sembra che nessun incantesimo di forzaAttivo setAttivo setMinimized (false) setFocus forceFocus e setVisible può realizzare questa cosa.

Sono abbastanza sicuro che sia possibile (almeno in Windows), come l'E Text Editor lo fa. Beh, questo non è swt, ma almeno alcune altre app have been known to do it.

Sto pensando che questo sia swt bug 192036?

Molte grazie.

correlati:

+0

Sembra che il bug SWT che hai collegato a ** esattamente ** descrive il tuo problema, e sembra che non saranno in grado di risolverlo. –

+0

Penso che sia davvero il problema per Windows - buona cattura. Per ovviare a questo problema, è necessario innanzitutto ridurre a icona una shell e quindi sbloccarla (oppure utilizzare un codice nativo [tramite ffi o jni] per forzare la memoria su di essa). In Linux non sono abbastanza sicuro di quale sia il problema (solo lampeggia nella barra delle applicazioni). Potrebbe * essere * corretto nelle versioni più recenti di swt.jar> = 3.5 https://bugs.eclipse.org/bugs/show_bug.cgi?id = 244597 – rogerdpack

risposta

5

http://github.com/rdp/redcar/commit/d7dfeb8e77f13e5596b11df3027da236f23c83f0

mostra come ho fatto in finestre, in ogni modo (usando FFI).

un paio di trucchi utile "può" essere

aggiungere un 'sonno 0.1' dopo il BringToFront.SetForegroundWindow (voluto) chiamata (si spera questo non è effettivamente necessario).

aggiungi uno shell.set_active dopo hai portato la finestra in primo piano. Per qualche ragione forceActive non chiama setActive.

NB che setActive esegue una chiamata BringWindowToTop utente32.dll e deve essere eseguita prima di scollegare l'input del thread.

Si noti inoltre che appare se si può fare si chiama nel giusto ordine potrebbe non essere necessario utilizzare l'hack di ingresso filo a tutti (?)

http://betterlogic.com/roger/?p=2950

(contiene diversi buoni suggerimenti su come a effettivamente fare questo destra)

su Linux, forceActive fa lavoro - ma solo fino a quando si sposta in un altro paio di finestre ,, poi lampeggia nella barra delle applicazioni, dopo che (solo). Indovina errore. [1]

legato anche:

How to bring a window to the front?

http://github.com/jarmo/win32screenshot/blob/master/lib/win32/screenshot/bitmap_maker.rb#L110 "set_foreground", che sembra funzionare con sia XP e Windows 7

[1] Need to bring application to foreground on Windows e https://bugs.eclipse.org/bugs/show_bug.cgi?id=303710

4

Questo è in realtà una funzionalità di Windows, che può essere attivata tramite il tweak UI power toy (almeno per Windows XP). Quando è abilitato, l'O/S impedisce deliberatamente ad una finestra di forzare se stessa come finestra focalizzata per impedirgli di "rubare lo stato attivo". In quanto tale, l'azione per catturare l'attenzione è cambiata semplicemente lampeggiando l'icona della barra delle applicazioni - poiché l'O/S sta deliberatamente convertendo l'azione su richiesta dell'utente, non ci sarà nulla che tu possa fare al riguardo (e questa è una buona cosa).

Questo è stato (probabilmente) fatto perché quindi molte applicazioni hanno abusato dell'API del bring-to-front e il comportamento ha disturbato gli utenti e li ha indotti a immettere nell'applicazione sbagliata.

+0

Se cerchi google per forceForeGround, vedrai un aggiramento, nel bene o nel male (presumo che questo sia ciò che awt usa per il suo metodo toFront, di cui swt non sembra). Sono d'accordo che forceActive dovrebbe essere usato con parsimonia :) – rogerdpack

+1

Ugh, sì, ci sono ancora troppe app che spuntano dallo sfondo, rubando input mentre eri impegnato a digitare qualcos'altro. Ho sperimentato la perdita di dati da questo prima. Viene visualizzata l'app in background "Eliminare blah?" mentre sto digitando qualcos'altro che sembra contenere il selettore per "Sì". Argh. –

2
private static void onTop(Shell shell) { 
     int s = -1; 
     Shell[] shells = display.getShells(); 
     for (int i = 0; i < shells.length; ++i) { 
      if (!shells[i].equals(shell)) { 
       shells[i].setEnabled(false); 
       shells[i].update(); 
      } else { 
       s = i; 
      } 
     } 
     while (!shell.isDisposed()) { 
      if (!display.readAndDispatch()) 
       display.sleep(); 
     } 
     for (int i = 0; i < shells.length; ++i) { 
      if (i != s) { 
       shells[i].setEnabled(true); 
       shells[i].update(); 
      } 
     } 
    } 
4

questo ha funzionato per me su Windows 7 e Ubuntu:

private void bringToFront(final Shell shell) { 
    shell.getDisplay().asyncExec(new Runnable() { 
     public void run() { 
      shell.forceActive(); 
     } 
    }); 
} 
2

Bug 192036 - Shell.forceActive doesn't raise a window above all other windows

@rogerdpack's query on Eclipse bug tracker è stato risposto con il seguente dirty workaround facendo quello che ci serve.

public void forceActive(Shell shell) { 
    int hFrom = OS.GetForegroundWindow(); 

    if (hFrom <= 0) { 
     OS.SetForegroundWindow(shell.handle); 
     return; 
    } 

    if (shell.handle == hFrom) { 
     return; 
    } 

    int pid = OS.GetWindowThreadProcessId(hFrom, null); 
    int _threadid = OS.GetWindowThreadProcessId(shell.handle, null); 

    if (_threadid == pid) { 
     OS.SetForegroundWindow(shell.handle); 
     return; 
    } 

    if (pid > 0) { 
     if (!OS.AttachThreadInput(_threadid, pid, true)) { 
     return; 
     } 
     OS.SetForegroundWindow(shell.handle); 
     OS.AttachThreadInput(_threadid, pid, false); 
    } 

    OS.BringWindowToTop(shell.handle); 
    OS.UpdateWindow(shell.handle); 
    OS.SetActiveWindow(shell.handle); 
    } 
1

C'è un modo per farlo funzionare con quello che inizialmente provato. In realtà è necessario chiamare shell.setMinimized(false) e successivamente quello shell.setActive() per ripristinare lo stato precedente di shell. Tuttavia,, funziona solo se lo shell era veramente nello stato ridotto al minimo. Quindi ecco la mia soluzione finale, che minimizza artificialmente il shell se non fosse già minimizzato. Il costo è un'animazione rapida se la minimizzazione deve essere eseguita.

shell.getDisplay().syncExec(new Runnable() { 

    @Override 
    public void run() { 
     if (!shell.getMinimized()) 
     { 
      shell.setMinimized(true); 
     } 
     shell.setMinimized(false); 
     shell.setActive(); 
    } 
});