2010-02-23 9 views
15

Actualmente, con swt, a veces quiero que un programa aparezca arbitrariamente (como podría ser un despertador).¿Cómo fuerza un programa swt de Java a "moverse al primer plano"?

típicamente los siguientes trabajos (JRuby):

@shell.setMinimized(false) 
@shell.forceActive 

Esto trae la cáscara para la parte delantera si se reduce al mínimo.

La creación de un nuevo caparazón en cualquier momento también trae el (nuevo caparazón) al frente.

Hasta ahora todo bien, sin embargo, si el shell es no minimizado, el código anterior simplemente muestra (parpadea) el icono de la aplicación en la barra de tareas. Bueno, en realidad la primera vez que lo ejecutas, lo lleva al frente. Después de eso, solo parpadea en la barra de tareas. Eso es Windows. En Linux, parece que solo parpadea en la barra de tareas (predeterminado de ubuntu).

¿Alguien sabe de una forma de plataforma cruzada para hacer que la aplicación salga al frente, en swt?

Parece que ningún encantamiento de fuerzaActive setActive setMinimized (false) setFocus forceFocus y setVisible pueden lograr esto.

Estoy bastante seguro de que es posible (al menos en Windows), como lo hace el Editor de texto E. Bueno, eso no es swt, pero al menos algunas otras aplicaciones have been known to do it.

Estoy pensando que tal vez es swt bug 192036?

Muchas gracias.

relacionadas:

+0

Parece que el error de SWT con el que se vincula ** exactamente ** describe su problema, y ​​parece que no van a poder arreglarlo. –

+0

Creo que ese es realmente el problema para Windows: buena captura. El trabajo por ahora es primero minimizar un shell y luego minimizarlo (o usar algún código nativo [a través de ffi o jni] para forzarlo hacia delante). Sin embargo, en Linux no estoy seguro de cuál es el problema (solo parpadea en la bandeja de tareas). * Se puede * arreglar * en las versiones más recientes de swt.jar> = 3.5 https://bugs.eclipse.org/bugs/show_bug.cgi?id = 244597 – rogerdpack

Respuesta

5

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

muestra cómo lo hice en las ventanas, de todos modos (usando FFI).

Un par de trucos útiles "puede" ser

añadir un 'sueño 0,1' después de que el BringToFront.SetForegroundWindow (quería) llamada (esperemos que éste no es realmente necesario).

agregar un shell.set_active después de ha llevado la ventana al primer plano. Por alguna razón, forceActive no llama a setActive.

NB que setActive hace una llamada a user32.dll BringWindowToTop, y debe hacerse antes de desconectar la entrada de subprocesos.

Tenga en cuenta también que parece que si se puede hacer que las llamadas en el orden correcto puede que no necesite utilizar el truco de entrada de hilo en absoluto (?)

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

(contiene varios buenos consejos sobre cómo para hacer realidad este derecho )

en Linux, forceActive hace el trabajo - pero sólo hasta que se mueva a otro par de ventanas ,, entonces parpadea en la barra de tareas después de que (sólo). Adivinando swt bug. [1]

También relacionado:

How to bring a window to the front?

http://github.com/jarmo/win32screenshot/blob/master/lib/win32/screenshot/bitmap_maker.rb#L110 "set_foreground" que parece funcionar con tanto XP y Windows 7

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

4

Este es en realidad una característica de Windows, que se puede habilitar a través del juguete de poder Tweak UI (al menos para Windows XP). Cuando está habilitado, el O/S evita deliberadamente que una ventana se fuerce a ser la ventana enfocada para evitar que se "robe el foco". Como tal, la acción para captar el foco cambia a solo parpadear el icono de la barra de tareas, dado que el O/S está convirtiendo deliberadamente la acción a petición del usuario, no habrá nada que puedas hacer al respecto (y esto es bueno).

Esto fue (probablemente) hecho porque así que muchas aplicaciones abusaron de la API de traer al frente y el comportamiento molestó a los usuarios y los hizo ingresar en la aplicación incorrecta.

+0

Si buscas en Google for forceForeGround verás una solución alternativa, para bien o para mal (supongo que esto es lo que usa awt para su método front, del cual swt no parece). Estoy de acuerdo en que ForceActive debería usarse con moderación :) – rogerdpack

+1

Ugh, sí, todavía hay demasiadas aplicaciones que aparecen de fondo, robando datos mientras estaba ocupado escribiendo algo más. He experimentado la pérdida de datos de esto antes. La aplicación de fondo aparece "¿Quieres borrar bla?" mientras estoy escribiendo algo más que contiene el selector para "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

Esto funcionó para mí en Windows 7 y 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 fue respondida con la siguiente dirty workaround hacer lo que necesitamos.

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

Hay una manera de hacerlo funcionar con lo que inicialmente probó. De hecho, necesita llamar al shell.setMinimized(false) y después de eso shell.setActive() para restaurar el estado anterior de shell. Sin embargo,, que solo funciona si el shell estaba realmente en el estado minimizado. Así que aquí está mi solución final, que minimiza artificialmente el shell si no se ha minimizado. El costo es una animación rápida si se tiene que hacer la minimización.

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

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