javafxtextareachangelistener

JavaFX: Place caret/cursor at end of TextArea when tabbing into TextArea


(Searching on stackoverflow, I've seen this question addressed for Javascript but not for JavaFX)

I have a TextArea that is effectively the primary text editor in a word-processor-like application (i.e., I intend the user to spend a lot of time working inside this TextArea). When the user tabs into the TextArea, I would like the cursor to be placed at the end of the TextArea so that the user can continue editing from the end of what they last typed.

I've implemented this using a ChangeListener (code below) and it has the desired behavior. However, since the cursor is placed at the end of the TextArea every time the focus is gained, then if I were to switch applications and then switch back, the cursor gets moved. This is inconvenient if, for instance, the user is typing a sentence somewhere in the middle of the TextArea, switches over to read an email, then switches back to find that their cursor has moved.

Is there a focus traversal policy that does this or some other way to implement this so that the cursor is moved to the end only when the user tabs into the TextArea? It seems to me that this would be commonly desired behavior: to have the cursor always appear at the end of a TextArea whenever the TextArea is tabbed into, but otherwise leave the cursor unmoved.

TextArea passageTextArea;

passageTextArea.focusedProperty().addListener(new ChangeListener<Boolean>() {
    @Override
    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue)
    {
        if (newValue.booleanValue()) {
            passageTextArea.positionCaret(passageTextArea.getText().length());
        }
    }
});

Solution

  • You can add an EventHandler for KeyEvent which moves the caret to the end of the text, when you press the Tab key:

     EventHandler<KeyEvent> tabListener = evt -> {
                if (evt.getCode() == KeyCode.TAB && !evt.isShiftDown()) {
                    evt.consume();
                    passageTextArea.requestFocus();
                    passageTextArea.end();
                }
            };
    
     node.addEventHandler(KeyEvent.ANY, tabListener);