2008-09-15 14 views
7

Para la mayoría de las GUI que he usado, cuando un control que contiene texto se enfoca, se selecciona todo el contenido del control. Esto significa que si solo comienza a escribir, reemplaza completamente los contenidos anteriores.¿Existe alguna manera fácil de cambiar el comportamiento de un control Java/Swing cuando se enfoca?

Ejemplo: Tiene control de giro que se inicializa con el valor cero. Usted tabula y escribe "1" El valor en el control ahora es 1.

Con Swing, esto no sucede. El texto en el control no está seleccionado y el quilate aparece en un extremo u otro del texto existente. Continuando con el ejemplo anterior:

Con un JSpinner giratorio, cuando se desplaza hacia el control giratorio, el quilate está a la izquierda. Escribe "1" y el valor en el control ahora es 10.

Esto me impulsa a mí (y a mis usuarios) a una pared y me gustaría cambiarlo. Aún más importante, me gustaría cambiarlo globalmente para que el nuevo comportamiento se aplique a JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner, y más. La única forma en que he encontrado esto es para agregar un FocusAdapter a cada control y anular el método focusGained() para Do The Right Thing [tm].

Tiene que haber una manera más fácil y menos frágil. ¿Por favor?

EDITAR: Una información adicional para este caso en particular. El formulario con el que estoy trabajando se generó utilizando el diseñador de formularios de Idea. Eso significa que normalmente no escribo el código para crear los componentes. Es posible decirle a Idea que quiere crearlos usted mismo, pero eso es una molestia que me gustaría evitar.

Lema: Todos los buenos programadores son básicamente flojos.

+0

Encontré una solución que satisface mis necesidades. Está publicado como una respuesta. –

Respuesta

1

Después de leer las respuestas hasta el momento me pasó el JPanel más exteriores con el siguiente método:

void addTextFocusSelect(JComponent component){ 
    if(component instanceof JTextComponent){ 
     component.addFocusListener(new FocusAdapter() { 
       @Override 
       public void focusGained(FocusEvent event) { 
        super.focusGained(event); 
        JTextComponent component = (JTextComponent)event.getComponent(); 
        // a trick I found on JavaRanch.com 
        // Without this, some components don't honor selectAll 
        component.setText(component.getText()); 
        component.selectAll(); 
       } 
      }); 

    } 
    else 
    { 
     for(Component child: component.getComponents()){ 
      if(child instanceof JComponent){ 
       addTextFocusSelect((JComponent) child); 
      } 
     } 
    } 
} 

Funciona!

+0

+1 para el truco 'setText (getText())'; Había resuelto todo lo demás por mí mismo, ¡pero todavía no funcionaba! –

0

La única forma que conozco es crear un FocusListener y conectarlo a su componente. Si desea que este FocusListener sea global para todos los componentes de su aplicación, puede considerar el uso de la Programación Orientada a Aspectos (AOP). Con AOP es posible codificar una vez y aplicar su enfoque oyente a todos los componentes instanciados en su aplicación sin tener que copiar y pegar el component.addFocusListener (oyente) código a través de su aplicación ..

Su aspecto sería tiene que interceptar la creación de un JComponent (o las subclases a las que desea agregar este comportamiento) y agregar el oyente de enfoque a la instancia recién creada. El enfoque AOP es mejor que copiar y pegar el FocusListener a todo tu código porque lo mantienes todo en una sola pieza de código, y no creas una pesadilla de mantenimiento una vez que decides cambiar tu comportamiento global, como quitar al oyente por JSpinners.

Hay muchos frameworks de AOP para elegir. Me gusta JBossAOP ya que es Java 100% puro, pero es posible que desee echar un vistazo a AspectJ.

2

Cuando he necesitado esto en el pasado, he creado subclases de los componentes. También quería agregar la función de "limpieza automática". por ejemplo:

public class AutoClearingTextField extends JTextField { 
    final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){ 
     @Override 
     public void focusLost(FocusEvent e) { 
     //onFocusLost(e); 
     } 

     @Override 
     public void focusGained(FocusEvent e) { 
     selectAll(); 
     } 
    }; 

    public AutoClearingTextField(String string) { 
     super(string); 
     addListener(); 
    } 

    private void addListener() { 
     addFocusListener(AUTO_CLEARING_LISTENER);  
    } 
} 

El mayor problema es que no he encontrado una forma "buena" para obtener todos los constructores estándar sin necesidad de escribir las anulaciones. Agregarlos y forzar una llamada a addListener es el enfoque más general que he encontrado.

Otra opción es observar ContainerEvents en un contenedor de nivel superior con un ContainerListeer para detectar la presencia de nuevos widgets y agregar un escucha de foco correspondiente basado en los widgets que se han agregado.(por ej .: si el evento del contenedor es causado al agregar un TextField, entonces agregue un detector de enfoque que sepa cómo seleccionar todo el texto en un TextField, y así sucesivamente.) Si se agrega un Contenedor, entonces necesita agregar recursivamente el ContainerListener a ese nuevo sub-contenedor también.

De cualquier manera, no tendrá que ensuciarse con los oyentes de enfoque en su código de UI real; todo se resolverá en un nivel superior.

2

No he probado esto por mí mismo (sólo incursionado en ella hace un tiempo), pero es probable que pueda obtener el componente con foco actual mediante el uso de: KeyboardFocusManager (hay un método estático getCurrentKeyboardFocusManager()) una adición de un PropertyChangeListener lo. A partir de ahí, puede averiguar si el componente es un JTextComponent y seleccionar todo el texto.

+0

+1 Según mi experiencia, esta es la mejor solución si tiene muchos controles y/o usa un diseñador de formularios visuales. –

2

Se puede escribir una clase separada que conecte un FocusListener al campo de texto deseado. Todo lo que el oyente de enfoque haría es llamar a selectAll() en el widget de texto cuando gana el foco.

public class SelectAllListener implements FocusListener { 
    private static INSTANCE = new SelectAllListener(); 

    public void focusLost(FocusEvent e) { } 

    public void focusGained(FocusEvent e) { 
    if (e.getSource() instanceof JTextComponent) { 
     ((JTextComponent)e.getSource()).selectAll(); 
    } 
    }; 

    public static void addSelectAllListener(JTextComponent tc) { 
    tc.addFocusListener(INSTANCE); 
    } 

    public static void removeSelectAllListener(JTextComponent tc) { 
    tc.removeFocusListener(INSTANCE); 
    } 
} 

Al aceptar un JTextComponent como argumento este comportamiento se puede añadir a JTextArea, JPasswordField, y todos los demás componentes de edición de texto directamente. Esto también permite que la clase agregue seleccionar todo a cuadros combinados editables y JSpinners, donde su control sobre el componente del editor de texto puede ser más limitado. métodos de conveniencia se pueden añadir:

public static void addSelectAllListener(JSpinner spin) { 
    if (spin.getEditor() instanceof JTextComponent) { 
    addSelectAllListener((JTextComponent)spin.getEditor()); 
    } 
} 

public static void addSelectAllListener(JComboBox combo) { 
    JComponent editor = combo.getEditor().getEditorComponent(); 
    if (editor instanceof JTextComponent) { 
    addSelectAllListener((JTextComponent)editor); 
    } 
} 

Además, los métodos de eliminación del oyente es probable que no sean necesarios, ya que el oyente no contiene referencias exteriores a cualquier otra instancia, pero se pueden agregar para hacer revisiones de código van más suave. (! Gracias)

Cuestiones relacionadas