7

我在我的程序中使用了一些 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 方法来分配当前对象,但不确定如何使这个“安全”(例如,它们是否需要同步?)。

也许我缺少一些东西?

4

4 回答 4

12

您需要使用 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);
于 2010-02-04T18:10:46.600 回答
7

这实际上发生在 中AbstractFormatter.install(JFormattedTextField),当字段获得焦点时调用。

我不确定为什么要这样设计,但是您可以覆盖此行为(只要您的格式化程序不更改字段中字符串的长度。)

示例(假设字段值为 an 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分隔数字组的 a,例如"1,000,000". 这使得任务更难,因为它改变了字符串的长度。

于 2010-02-04T18:14:51.853 回答
1

我认为对 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);
}
于 2013-07-03T07:18:44.123 回答
0

如果您不能或不想覆盖格式化程序:

    import java.awt.event.FocusEvent;
    import java.awt.event.FocusListener;
    import java.text.NumberFormat;
    
    import javax.swing.JFormattedTextField;
    import javax.swing.JOptionPane;
    import javax.swing.SwingUtilities;
    import javax.swing.text.NumberFormatter;
    
    public class TestJFormattedTextFieldFocus {
    
        public static void main(String[] args) {
            NumberFormat format = NumberFormat.getInstance();
            NumberFormatter formatter = new NumberFormatter(format);
            JFormattedTextField field = new JFormattedTextField(formatter);
            field.addFocusListener(new FocusListener() {
    
                @Override
                public void focusLost(FocusEvent e) {
                }
    
                @Override
                public void focusGained(FocusEvent e) {
                    restoreCaretPosition();
                }
    
                private void restoreCaretPosition() {
                    int caretPosition = field.getCaretPosition();
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            field.setCaretPosition(caretPosition);
                        }
                    });
                }
            });
            field.setValue(1234567890);
            JOptionPane.showMessageDialog(null, field);
        }
    
    }
于 2021-04-10T16:46:28.443 回答