2012-03-12 13 views
7

Tengo una aplicación Java Swing que genera diálogos secundarios con controles de texto. Y el problema es que cuando cambia el diseño del teclado en el cuadro de diálogo secundario, cambia de nuevo justo después de que se cierra el cuadro de diálogo.¿Preservar el diseño del teclado en la aplicación swing?

Lo que necesito es el diseño de la placa de contacto para permanecer después de ser cambiado, ya sea que se haya cambiado en el cuadro principal o en un cuadro secundario.

Aquí es una SSCCE que ilustra el problema:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

public class InheritInputContext { 

    public static void main(String[] arg) { 
     final MainFrame mainFrame = new MainFrame(); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       mainFrame.setPreferredSize(new Dimension(300, 400)); 
       mainFrame.pack(); 
       mainFrame.setLocationRelativeTo(null); 
       mainFrame.setVisible(true); 
      } 
     }); 

    } 
} 


class MainFrame extends JFrame { 

    MainFrame() { 
     setLayout(new BorderLayout()); 
     JTextArea textArea = new JTextArea(); 
     add(textArea, BorderLayout.CENTER); 

     JButton dialogBtn = new JButton("Dialog"); 
     add(dialogBtn, BorderLayout.SOUTH); 
     dialogBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       ChildDialog cd = new ChildDialog(MainFrame.this); 
       cd.setPreferredSize(new Dimension(200, 200)); 
       cd.setLocationRelativeTo(MainFrame.this); 
       cd.pack(); 
       cd.setVisible(true); 
      } 
     }); 
    } 
} 


class ChildDialog extends JDialog { 

    ChildDialog(Window w) { 
     super(w); 
     JTextArea textArea = new JTextArea(); 
     getContentPane().add(textArea); 
    } 
} 
+1

¿Estás hablando de la disposición del teclado del sistema operativo? Un poco confundido aquí. –

Respuesta

2

Ok, acabo de asentar con esta solución:

añade un detector de conjunto de herramientas Java en el método main() de esta manera:

AWTEventListener awtWindowListener = new AWTEventListener() { 
    @Override 
    public void eventDispatched(AWTEvent event) { 
     if (event instanceof WindowEvent) { 
      if (WindowEvent.WINDOW_CLOSED == event.getID() 
        || WindowEvent.WINDOW_CLOSING == event.getID()) { 
       Window child = ((WindowEvent) event).getWindow(); 
       Window parent = SwingUtilities.getWindowAncestor(child); 
       if (parent == null) return; 
       InputContext childIC = child.getInputContext(); 
       parent.getInputContext().selectInputMethod(childIC.getLocale()); 
      } 
     } 

    } 
}; 

Toolkit.getDefaultToolkit().addAWTEventListener(awtWindowListener, AWTEvent.WINDOW_EVENT_MASK); 

Funciona en todos los diálogos secundarias generadas con la ventana padre como parámetro de constructor En un evento cercano, la configuración regional de InputContext del cuadro de diálogo secundario se coloca en InputContext de su ventana principal.

Aunque puede haber una forma mejor.

1

simplemente estás buscando una manera de tener cualquier cambio diseño afecta a su aplicación a nivel mundial?

Si es así, un enfoque es crear un oyente personalizado, hacer que los diversos componentes que se preocupan por el cambio de diseño muestren su interés en dichos eventos y luego desencadenar un evento de diseño de cambio que desencadena el cambio en todos los componentes cuando es cambios en cualquiera de ellos.

Otra forma de hacerlo sería almacenar las propiedades de diseño en un objeto que sea accesible para cualquiera de los componentes, y hacer que actualicen su diseño periódicamente a través de un temporizador. Esto sería menos deseable, sin embargo, porque probablemente habría muchas actualizaciones innecesarias frente al modo de operación "solo actualización en el evento". Supongo que los usuarios de su aplicación no cambiarán el diseño de su teclado más de una o dos veces por sesión (a diferencia de cada 5 segundos).

Otra, tercera manera, para hacer esto es tener la configuración del diseño del teclado almacenada en el nivel de la aplicación y cargada al inicio. Luego, cuando ocurre un cambio en el diseño del teclado, solicite al usuario que reinicie la aplicación para que los cambios surtan efecto de manera global.

+0

Sí, estoy buscando una manera de preservar cualquier cambio de diseño realizado en la aplicación, para evitar la necesidad de cambiar el diseño una y otra vez en cada diálogo nuevo. En este momento estoy explorando la opción de utilizar AWTEventListener en el nivel de la aplicación, para evitar escribir código adicional para cada fotograma infantil – yggdraa

+0

La actualización del temporizador está fuera de toda duda, sería una sobrecarga. Preguntar por la recarga de aplicaciones tampoco está claro, el usuario debe cambiar entre 2 idiomas todo el tiempo. – yggdraa

+0

Miré en NetBeans e Intellijiadea también, hay la misma cosa. Abre Configuración, por ejemplo, cambia el idioma de entrada, cierra Configuración y el diseño del teclado vuelve a ser lo que solía ser antes. En otras aplicaciones (navegadores, mssql, bloc de notas), el cambio del diseño del teclado es constante en toda la aplicación. – yggdraa

1

Sí y no: el código de yggdraa del 13 de marzo funcionó bien en Windows pero falló en Linux.

Puede que no haya ninguna solución universal para Linux: no hay elementos tales como Windows 'GetKeyboardLayout() y ActivateKeyboardLayout() allí. Algunos hacks dependientes de la configuración podrían ser posibles, como analizar la salida de xset (details here) y forzar el diseño, por ejemplo, en la tecla arriba/abajo.

En el ejemplo anterior, el código de selección de entrada en eventDispatched() se llama demasiado tarde, cuando el teclado del sistema operativo ya ha cambiado al sistema predeterminado de EE. UU.

Algunos intentos de fuerza bruta tampoco funcionaron: myParticularJField.setLocale (myForcedLocale) del controlador de enfoque del campo se deshace inmediatamente al presionar la primera tecla. Lo mismo para forzar la configuración regional de nivel superior (JFrame/JDialog).

Actualización:

Tenemos sólo para Windows en la producción, por lo que esto funcione bajo Linux es poco práctico: demasiado esfuerzo.

Por las dudas, un subproducto. Esto determina correctamente qué diseño está activo actualmente: predeterminado o alternativo ("local"). No puede distinguir entre varios diseños alternativos:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

public class LinuxKeyboardLayoutStatus { 

    public enum LayoutType { DEFAULT, LOCAL } 

    public LinuxKeyboardLayoutStatus.LayoutType getCurrentKeyboardLayoutType() throws IOException, InterruptedException { 
     String[] command = createCommand(); 
     Process p = Runtime.getRuntime().exec(command); 
     BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     String l = r.readLine(); 
     r.close(); 
     p.waitFor(); 
     return decodeLayoutType(l); 
    } 

    protected String[] createCommand() { 
     return new String[] { "/bin/sh", "-c", "xset -q | grep LED | awk '{ print $10 }' | cut -c5" }; 
    } 

    protected LinuxKeyboardLayoutStatus.LayoutType decodeLayoutType(String commandOutput) { 
     return 
      commandOutput != null && !commandOutput.equals("0") ? LayoutType.LOCAL : LayoutType.DEFAULT; 
    } 

} 

Actualización:

En Ubuntu, el cambio de nuevo al diseño por defecto que ocurre en el nivel de la ventana X (eventos DBus). Una solución: para desactivar los diseños por separado para cada ventana: Configuración => Teclado => Diseños, desmarque "Diseño separado para cada ventana".

Cuestiones relacionadas