Как мне (должно) заставить поле отражать свое значение сразу после его установки (даже если поле все еще удерживает фокус)?
- repaint(), revalidate() в коде прослушивателя свойств не имеют никакого эффекта.
- Я могу установить текст вручную, но это вызовет ненужный вызов stringToValue(), по сути вычисляя одно и то же значение заново. Это неприемлемо.
- Я также обнаружил, что сброс значения работает, но на мой взгляд выглядит очень некрасиво. Для любого читателя кода далеко не очевидно, что такая необычная строка перерисовывает значение в поле (или что она вообще делает). Кроме того, он устанавливает курсор на ноль — я, с другой стороны, предпочел бы, чтобы он оставался там, где он есть (см. трассировку стека внизу). Я уверен, что нужно сделать это по-другому.
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());
}
}
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;
}
}
После ввода «Алекс» и нажатия Enter:
Value changed. New value: null
Value changed. New value: Person Alex

Трассировка стека курсоров для элемента 3:
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)
Подробнее здесь: https://stackoverflow.com/questions/798 ... -new-value
Мобильная версия