2010-02-04 17 views
7

Estoy utilizando algunos JFormattedTextFields en mi programa. Por alguna razón, cuando el campo de texto gana enfoque después de hacer clic en el campo de texto, la posición de intercalación siempre salta hacia la izquierda (posición 0). Me gustaría que el cursor finalice en la ubicación en la que el usuario hizo clic. Entonces, si hago clic entre dos dígitos, el símbolo de intercalación debería estar entre esos dos dígitos.JFormattedTextField posición de cursor en el foco

Así que implementé un FocusListener que obtendría la ubicación del clic y establecería la posición de intercalación allí.

FocusListener focusListener = new FocusListener(){ 


    public void focusGained(FocusEvent evt) { 

     JFormettedTextField jftf = (JFormattedTextField) evt.getSource(); 

     //This is where the caret needs to be. 
     int dot = jftf.getCaret().getDot(); 

     SwingUtilities.invokeLater(new Runnable() { 

     public void run() { 
'the textField that has focus'.setCaretPosition('Some how get the evt or dot');    
       } 
      }); 
     } 

    public void focusLost (FocusEvent evt) {} 

    }); 

He intentado varias cosas para que funcione. Intenté usar la palabra clave final, que funciona, pero solo para un solo campo de texto.

He utilizado los métodos set/get dentro del detector de enfoque para asignar el objeto actual, pero no estoy seguro de cómo hacer que esto sea "seguro" (por ejemplo, ¿tienen que estar sincronizados?).

Quizás haya algo que me falta?

Respuesta

10

Es necesario utilizar un MouseListener:

MouseListener ml = new MouseAdapter() 
{ 
    public void mousePressed(final MouseEvent e) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       JTextField tf = (JTextField)e.getSource(); 
       int offset = tf.viewToModel(e.getPoint()); 
       tf.setCaretPosition(offset); 
      } 
     }); 
    } 
}; 

formattedTextField.addMouseListener(ml); 
+0

¡Buena respuesta! ¿Pero por qué necesitas hacerlo en invokeLater()? ¿MousePressed() no se invoca desde el subproceso de evento de todos modos? – Jonas

+2

@Sanoj, la demora introducida por 'invokeLater' es necesaria para que funcione. Normalmente, cuando se hace clic en el campo, gana foco, lo que hace que el formateador vuelva a formatear el valor y actualice el texto del campo. Un efecto colateral de eso es que el caret se mueve. Con 'invokeLater', este método' run() 'no se ejecuta hasta que se haya completado el manejo del evento de enfoque, así que sabes que una vez que coloques el cursor en el lugar correcto, permanecerá allí. – finnw

+0

¡Gracias por la explicación! – Jonas

7

Esto sucede realmente en AbstractFormatter.install(JFormattedTextField), que se llama cuando las ganancias de campo se centran.

no estoy seguro de por qué se ha diseñado de esta manera, pero se puede anular este comportamiento (siempre y cuando su formateador no cambia la longitud de la cadena en el campo.)

Ejemplo (asumiendo que el campo valor es un int):

class IntFormatter extends AbstractFormatter { 
    @Override 
    public void install(final JFormattedTextField ftf) { 
     int prevLen = ftf.getDocument().getLength(); 
     int savedCaretPos = ftf.getCaretPosition(); 
     super.install(ftf); 
     if (ftf.getDocument().getLength() == prevLen) { 
      ftf.setCaretPosition(savedCaretPos); 
     } 
    } 

    public Object stringToValue(String text) throws ParseException { 
     return Integer.parseInt(text); 
    } 

    public String valueToString(Object value) throws ParseException { 
     return Integer.toString(((Number) value).intValue()); 
    } 
} 

Tenga en cuenta que esto no es el mismo que el valor por defecto Integer formateador. El formateador predeterminado usa un DecimalFormat que separa grupos de dígitos, p. Ej. "1,000,000". Esto hace que la tarea sea más difícil ya que cambia la longitud de la cadena.

1

Mejorado en la solución de finnw un poco, creo. Ejemplo:

public static void main(String[] args) { 
    NumberFormat format = NumberFormat.getInstance(); 
    NumberFormatter formatter = new NumberFormatter(format) { 
     @Override 
     public void install(JFormattedTextField pField) { 
      final JFormattedTextField oldField = getFormattedTextField(); 
      final int oldLength = pField.getDocument().getLength(); 
      final int oldPosition = pField.getCaretPosition(); 

      super.install(pField); 

      if (oldField == pField && oldLength == pField.getDocument().getLength()) { 
       pField.setCaretPosition(oldPosition); 
      } 
     } 
    }; 
    JFormattedTextField field = new JFormattedTextField(formatter); 
    field.setValue(1234567890); 

    JOptionPane.showMessageDialog(null, field); 
} 
Cuestiones relacionadas