Search code examples
javaswingfocusjtextfieldcaret

What is the best way to position the caret at the end of a JTextField on focus?


By default, when a JTextField gains focus the caret is positioned at the beginning of the text. However, I think the better behavior is to position it at the end, or to select all the text, e.g. http://jsfiddle.net/Marcel/jvJzX/. What is a nice way to do this? Ideally, the solution would be applied globally to all JTextFields in the application.

Example of the default behavior (hit tab to focus the field):

public static void main(String[] args) {
    JTextField field = new JTextField("hello world!");
    JOptionPane.showMessageDialog(null, field);
}

Edit: To clarify, it would be nice if I didn't have to search through my app and change all the text fields.


Solution

  • Neither the actual behaviour nor the requirement are fully described:

    when a JTextField gains focus the caret is positioned at the beginning of the text

    that's not entirely true: when it gains focus by

    • clicking, the caret is placed at the mouse location
    • other means (tabbing, programmatic) it is placed at the position it had at the time focus was lost.

    Consequently, the requirement:

    the better behavior is to position it at the end, or to select all the text

    needs a bit of thought for those cases to not detoriate usability, at least for the first users might be confused if a mouse gesture would be overruled. The second is arguable and probably OS/LAF dependent. Personally, I wouldn't touch the caret if its position is not at the start.

    Technically, a solution to globally trigger changes of component state on focus changes is to register a PropertyChangeListener with the KeyboardFocusManager:

    PropertyChangeListener pl = new PropertyChangeListener() {
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (!(evt.getNewValue() instanceof JTextField)) return;
            JTextField field = (JTextField) evt.getNewValue();
            // crude check to not overdo it
            int dot = field.getCaretPosition();
            if (dot == 0) {
                field.selectAll();
            }
        }
    };
    KeyboardFocusManager.getCurrentKeyboardFocusManager()
        .addPropertyChangeListener("permanentFocusOwner", pl);