'How to control Caret position in trimmed TextField?

I have a TextField, in which I do a check after any changes are made. I also trim away any double spaces that were typed. Problem is that after I replace text with trimmed one, Caret position refreshes. I added calculating, so that Caret will go to position user last input, but it's not working properly with extra spaces. My code:

EventHandler<InputEvent> fieldChangeListener = new EventHandler<InputEvent>() {
            public void handle(InputEvent event) {
                TextField field = (TextField) event.getSource();

                int caretPos = field.getCaretPosition();

                String text = field.getText();
                text = text.replaceAll("\\s+", " ").trim();
                field.setText(text);
                field.positionCaret(caretPos);

                event.consume();}};

name.addEventHandler(KeyEvent.KEY_RELEASED, fieldChangeListener);

In picture user puts cursor before word 'Friend', presses space bar and extra space will get trimmed, placing Caret right after 'F'. If space bar will be hold longer, Caret will be placed in the end.

enter image description here

Desired result: Caret placed before word 'Friend'.

How would be better to do that?



Solution 1:[1]

The reason why the caret position is not working as expected is because you are not reducing the caret position when there is multiple space in the string. You should remove the caret position by the amount of removed multiple spaces.

In the code below, I check if the string has at least double spaces and if it does then i remove the spaces and also reduce the caret position by the number of spaces removed from the string.

 import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.InputEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Miner extends Application {


    @Override
    public void start(Stage primaryStage) throws Exception {
        AnchorPane pane  = new AnchorPane();
        TextField tf = new TextField("HELLO FRIEND");
        int CaretPos = tf.getCaretPosition();
        System.out.println("CaretPos = " + CaretPos);
        pane.getChildren().add(tf);

        EventHandler<InputEvent> fieldChangeListener = new EventHandler<InputEvent>() {
            public String AtLeastDoubleSpace = "  ";

            public void handle(InputEvent event) {
                TextField field = (TextField) event.getSource();
                String text = field.getText();
                String originalString = text;
                int caretPos;
                if(text.contains(AtLeastDoubleSpace)) {
                    caretPos = field.getCaretPosition();
                    text = text.replaceAll("\\s+"," ").trim();
                    field.setText(text);
                    int spacesRemoved = originalString.length() - text.length();
                    field.positionCaret(caretPos - spacesRemoved);
                    event.consume();
                } else {
                    caretPos = field.getCaretPosition();
                    field.setText(text);
                    field.positionCaret(caretPos);
                    event.consume();
                }

            }};

        tf.addEventHandler(KeyEvent.KEY_RELEASED, fieldChangeListener);

        Scene scene = new Scene(pane);
        primaryStage.setScene(scene);
        primaryStage.show();

    }



    public static void main(String[] args) {
        launch(args);
    }
}

I provided this solution depending upon my understanding to the question you provided. Let me know, if you need any further help.

Solution 2:[2]

how about caretPositionProperty and add listener??

textField.caretPositionProperty().addListener((ob, old1, new1) -> {
System.out.println("old:" + old1 + "  new " + new1);
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Rafael Gimenes