¿Cómo obliga a un programa swt de Java a "moverse hacia sí mismo al primer plano"?
shell user-interface (6)
En realidad, esta es una característica de Windows, que puede habilitarse a través del Tweak UI power toy (al menos para Windows XP). Cuando está habilitado, el O / S evita deliberadamente que una ventana se fuerce a sí misma como la ventana enfocada para detenerla "robando el foco". Como tal, la acción para captar el enfoque se cambia para que solo parpadee el icono de la barra de tareas, ya que O / S está convirtiendo deliberadamente la acción a petición del usuario, no habrá nada que pueda hacer al respecto (y esto es algo bueno).
Esto se hizo (probablemente) porque muchas aplicaciones abusaron de la API de acceso directo y el comportamiento molestó tanto a los usuarios como a la entrada de la aplicación incorrecta.
Actualmente con swt, a veces quiero que un programa venga arbitrariamente al primer plano (como lo haría un reloj de alarma).
Típicamente los siguientes trabajos (jruby):
@shell.setMinimized(false)
@shell.forceActive
Esto trae la cáscara al frente si se minimiza.
Crear un nuevo shell en cualquier momento también trae al (nuevo shell) al frente.
Hasta ahora todo bien, sin embargo, si el shell no está minimizado, el código anterior simplemente parpadea (parpadea) el icono de la aplicación en la barra de tareas. Bueno, en realidad la primera vez que lo ejecutas, lo trae al frente. Después de eso, simplemente parpadea en la barra de tareas. Eso es windows. En Linux, parece que solo parpadea en la barra de tareas (valor predeterminado de ubuntu).
¿Alguien sabe de una plataforma multiplataforma para que la aplicación llegue al frente, en swt?
Parece que ningún conjuro de forceActive 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 se sabe que al menos algunas otras aplicaciones lo hacen .
Estoy pensando que tal vez este es swt bug 192036 ?
Muchas gracias.
Relacionado:
- ¿Cómo traer una ventana al frente?
- Abriendo una concha
- Mantener la ventana en primer plano (incluso si pierde el foco)
- Error 244597 - No se puede activar la shell programáticamente en gtk
- Necesidad de llevar la aplicación a primer plano en Windows
- ¿Cómo traer una ventana al frente? este ejemplo de swing podría ser algún tipo de pista, también ...
Esto me funcionó en Windows 7 y Ubuntu:
private void bringToFront(final Shell shell) {
shell.getDisplay().asyncExec(new Runnable() {
public void run() {
shell.forceActive();
}
});
}
Hay una manera de hacerlo funcionar con lo que inicialmente probaste. En realidad, debe llamar a shell.setMinimized(false)
y después de ese shell.setActive()
para restaurar el estado anterior de la shell
. Sin embargo , eso 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 ya. El costo es una animación rápida si la minimización tiene que hacerse.
shell.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
if (!shell.getMinimized())
{
shell.setMinimized(true);
}
shell.setMinimized(false);
shell.setActive();
}
});
http://github.com/rdp/redcar/commit/d7dfeb8e77f13e5596b11df3027da236f23c83f0
muestra cómo lo hice en windows, de todos modos (usando ffi).
Un par de trucos útiles pueden ser
agregue un ''sleep 0.1'' después de la llamada BringToFront.SetForegroundWindow (wanted) (esperemos que esta no sea realmente necesaria).
agregue un shell.set_active después de haber traído la ventana al primer plano. Por alguna razón, forceActive no llama a setActive.
NB: que setActive realiza una llamada BringWindowToTop de user32.dll y debe realizarse antes de separar la entrada de subprocesos.
Tenga en cuenta también que, si puede hacer sus llamadas en el orden correcto, es posible que no necesite utilizar el truco de entrada de hilo (?)
http://betterlogic.com/roger/?p=2950
(contiene varios buenos consejos sobre cómo hacer esto correctamente )
En Linux, forceActive funciona, pero solo hasta que te muevas a otras pocas ventanas, luego parpadea en la barra de tareas (solo eso). Adivinando el error swt. [1]
También relacionado:
¿Cómo traer una ventana al frente?
http://github.com/jarmo/win32screenshot/blob/master/lib/win32/screenshot/bitmap_maker.rb#L110 "set_foreground" que parece funcionar tanto con xp como con windows 7
[1] Necesito llevar la aplicación a primer plano en Windows y https://bugs.eclipse.org/bugs/show_bug.cgi?id=303710
Error 192036 - Shell.forceActive no levanta una ventana sobre todas las demás ventanas
La consulta de @ rogerdpack en Eclipse bug tracker fue respondida con la siguiente solución sucia haciendo 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);
}
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();
}
}
}