Позиция курсора JFormattedTextField в фокусе
-
18-09-2019 - |
Вопрос
Я использую несколько JFormattedTextFields в своей программе.По какой-то причине, когда текстовое поле получает фокус после щелчка по текстовому полю, позиция курсора всегда смещается влево (позиция 0).Я бы хотел, чтобы курсор оказался в том месте, на которое щелкнул пользователь.Поэтому, если я щелкну между двумя цифрами, курсор должен оказаться между этими двумя цифрами.
Поэтому я реализовал FocusListener, который получал место щелчка и устанавливал там положение курсора.
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) {}
});
Я попробовал несколько вещей, чтобы заставить его работать.Я пробовал использовать ключевое слово Final, оно работает, но только для одного текстового поля.
Я использовал методы set/get внутри прослушивателя фокуса, чтобы назначить текущий объект, но не уверен, как сделать это «безопасным» (например,их нужно синхронизировать?).
Может быть, мне чего-то не хватает?
Решение
Вам нужно использовать 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);
Другие советы
На самом деле это происходит в AbstractFormatter.install(JFormattedTextField)
, который вызывается, когда поле получает фокус.
Я не уверен, почему он устроен таким образом, но вы можете переопределить это поведение (при условии, что ваш форматтер не меняет длину строки в поле).
Пример (предполагается, что значение поля является 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());
}
}
Обратите внимание, что это не то же самое, что и значение по умолчанию. Integer
форматтер.Средство форматирования по умолчанию использует DecimalFormat
который разделяет группы цифр, например. "1,000,000"
.Это усложняет задачу, поскольку изменяется длина строки.
Я думаю, что решение finnw немного улучшено.Пример:
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);
}