Code: Select all
JFormattedTextFieldÜberraschenderweise aktualisiert Wie kann (sollte) ich dafür sorgen, dass das Feld seinen Wert direkt nach dem Festlegen widerspiegelt (auch wenn das Feld noch den Fokus behält)?
- , revalidate() im Eigenschaften-Listener-Code haben keine Auswirkung.
Code: Select all
repaint() - Ich kann den Text manuell festlegen, aber es löst einen unnötigen Aufruf von stringToValue() aus, wodurch im Wesentlichen derselbe Wert noch einmal berechnet wird. Das ist nicht akzeptabel.
- Ich habe auch festgestellt, dass das Zurücksetzen des Werts zwar funktioniert, für mich aber sehr hässlich aussieht. Für jeden Leser des Codes ist es bei weitem nicht offensichtlich, dass eine solch ungewöhnliche Zeile den Wert im Feld neu zeichnet (oder was sie überhaupt bewirkt). Außerdem setzt es das Caretzeichen auf Null – ich hingegen würde es vorziehen, wenn es dort bleibt, wo es ist (siehe Stack-Trace unten). Ich bin mir sicher, dass ich es anders machen soll.
Code: Select all
import javax.swing.JFormattedTextField;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.JFormattedTextField.AbstractFormatterFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;
import java.awt.Component;
import java.awt.Container;
public class FormattedTextFieldDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("Formatted Text Field Demo");
frame.setContentPane(createMainPanel());
frame.setLocationRelativeTo(null);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static Container createMainPanel() {
JPanel panel = new JPanel();
panel.add(createTextField());
return panel;
}
private static Component createTextField() {
JFormattedTextField field = new JFormattedTextField();
field.setColumns(10);
field.setFormatterFactory(createFormatterFactory());
field.addPropertyChangeListener("value", e -> {
// 1. useless
// field.repaint();
// 2. works but triggers superfluous value computation
// field.setText(toString((Person) e.getNewValue()));
// 3. works but ugly (the equals() check is to avoid StackOverflowError)
// if (!Objects.equals(e.getOldValue(), e.getNewValue())) field.setValue(field.getValue());
System.out.printf("Value changed. New value: %s\n", e.getNewValue());
});
return field;
}
private static AbstractFormatterFactory createFormatterFactory() {
DefaultFormatterFactory formatterFactory = new DefaultFormatterFactory();
formatterFactory.setDefaultFormatter(createFormatter());
return formatterFactory;
}
private static AbstractFormatter createFormatter() {
AbstractFormatter formatter = new DefaultFormatter() {
@Override
public Object stringToValue(String string) {
return (string == null) ? null : new Person(string);
}
@Override
public String valueToString(Object value) {
return (value instanceof Person) ? FormattedTextFieldDemo.toString((Person) value) : null;
}
};
return formatter;
}
private static String toString(Person value) {
if (value == null) return null;
return String.format("Person %s", value.getName());
}
}
Code: Select all
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person " + name;
}
}
Code: Select all
Value changed. New value: null
Value changed. New value: Person Alex

Der Caret-Stack-Trace für Element 3:
Code: Select all
at javax.swing.text.DefaultCaret.setDot(DefaultCaret.java:1051)
at javax.swing.text.JTextComponent.setCaretPosition(JTextComponent.java:1631)
at javax.swing.text.DefaultFormatter.positionCursorAtInitialLocation(DefaultFormatter.java:333)
at javax.swing.text.DefaultFormatter.install(DefaultFormatter.java:126)
at javax.swing.JFormattedTextField.setFormatter(JFormattedTextField.java:464)
at javax.swing.JFormattedTextField.setValue(JFormattedTextField.java:788)
at javax.swing.JFormattedTextField.setValue(JFormattedTextField.java:501)
at demos.text.field.FormattedTextFieldDemo.lambda$createTextField$0(FormattedTextFieldDemo.java:39)
Mobile version