2010-02-04 17 views
7

ich ein paar JFormattedTextFields in meinem Programm bin verwendet. Wenn das Textfeld nach einem Klick auf das Textfeld den Fokus erhält, springt die Caret-Position aus irgendeinem Grund immer nach links (Position 0). Ich möchte, dass das Caret am vom Benutzer angeklickten Ort endet. Wenn ich also zwischen zwei Ziffern klicke, sollte der Cursor zwischen diesen beiden Ziffern stehen.JFormattedTextField Caretposition auf Fokus

So implementiert ich einen Focuslistener, die die Klickposition und stellen Sie die Position der Einfügemarke dort bekommen würde.

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) {} 

    }); 

Ich habe eine Reihe von Dingen versucht, um seine Arbeit zu bekommen. Ich habe versucht, das endgültige Schlüsselwort zu verwenden, das funktioniert, aber nur für ein einzelnes Textfeld.

Ich habe set/get-Methoden innerhalb des Fokus-Listeners verwendet, um das aktuelle Objekt zuzuweisen, bin mir aber nicht sicher, wie dies "sicher" gemacht werden soll (z. B. müssen sie synchronisiert werden?).

Vielleicht gibt es etwas, was ich bin fehlt?

Antwort

10

Sie benötigen einen Mouselistener verwenden:

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

Gute Antwort! Aber warum müssen Sie es in invokeLater() tun? Wird mousePressed() nicht trotzdem vom Event-Thread aufgerufen? – Jonas

+2

@Sanoj, Die von 'invokeLater' eingeführte Verzögerung ist notwendig, damit sie funktioniert. Wenn das Feld angeklickt wird, erhält es normalerweise den Fokus, wodurch der Formatierer den Wert neu formatiert und den Feldtext aktualisiert. Ein Nebeneffekt davon ist, dass der Caret verschoben wird. Mit 'invokeLater' wird diese' run() 'Methode nicht ausgeführt, bis die Fokusereignisbehandlung abgeschlossen ist, so dass Sie wissen, dass sobald Sie das Caretzeichen an der richtigen Stelle platzieren, es dort bleiben wird. – finnw

+0

Danke für die Erklärung! – Jonas

7

Das tatsächlich in AbstractFormatter.install(JFormattedTextField) geschieht, die aufgerufen wird, wenn das Feld des Fokus erhält.

Ich bin mir nicht sicher, warum es so gestaltet ist, aber Sie können dieses Verhalten außer Kraft setzen (solange Ihr Formatierer nicht die Länge der Zeichenfolge im Feld ändert.)

Beispiel (unter der Annahme, das Feld Wert ist ein 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()); 
    } 
} 

Beachten Sie, dass diese als Standard Integer Formatierer ist nicht das gleiche. Der Standardformatierer verwendet eine DecimalFormat, die Zifferngruppen trennt, z. "1,000,000". Dies erschwert die Aufgabe, da sich die Länge der Zeichenfolge ändert.

1

auf finnw-Lösung ein wenig verbessert, denke ich. Beispiel:

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); 
}