0

I'm implementing the AutoComplete logic in Javafx. A TextField is for user input and every time it got updated, the listener will be triggered. And then a dropdown menu which is a listView will display the matched results.

So the problem is that how can I get the updated caret position in TextField when the textProperty listener is in process?

I'm currently using textfield.getCaretPosition(), but it will only return the previous position.

Any inputs will be appreciated!

        commandTextField.textProperty().addListener(new ChangeListener<String>() {

            @Override
            public void changed(ObservableValue<? extends String> observable,
                                String oldText, String newText) {

                // Following line will return previous caret position
                commandTextField.getCaretPosition();

                ...//autocomplete logic omitted
            }
        });

EDIT: The reason that I need to get the caret position is that I need to know the position where the input is changed and show suggestions correspondingly.

            textField.caretPositionProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
                caretPosition = newValue.intValue();
            });

            textField.textProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {

                ...//autocomplete Logic
            }

In the above case, the textProperty listener will be invoked first and followed by caretPositionProperty, therefore there is no way to get updated caret position in my case.

  • 1
    Please create a [mcve] that demonstrates the issue it will help others to understand what your issue is exactly – Matt Oct 24 '19 at 12:52
  • looks like the internal update of the textField is not yet complete - try to use a TextFormatter – kleopatra Oct 24 '19 at 13:34
  • Alternatively I have seen some previously implemented AutoComplete ComboBox's you could take a look into something like that as well – Matt Oct 24 '19 at 14:09
  • Does this answer your question? [JavaFX TextField Auto-suggestions](https://stackoverflow.com/questions/36861056/javafx-textfield-auto-suggestions) – trilogy Jun 14 '20 at 00:33

2 Answers2

1

It's not the intended use of the API, but you could use a TextFormatter constructed with an UnaryOperator<TextFormatter.Change> as parameter. This is usually used to prevent/modify undesired changes to the text, but in this case we'll just use the Change object to get you the data you want.

The following example "suggests" possibilities each one replacing the selected section with some string:

@Override
public void start(Stage primaryStage) throws Exception {
    ListView<String> listView = new ListView<>();

    String[] replacements = { "foo", "bar", "42", "zap" };
    listView.getItems().setAll(replacements);

    TextField textField = new TextField();
    TextFormatter<?> formatter = new TextFormatter<>((UnaryOperator<TextFormatter.Change>) change -> {
        int a = change.getAnchor();
        int b = change.getCaretPosition();
        String newText = change.getControlNewText();

        String prefix = newText.substring(0, Math.min(a, b));
        String suffix = newText.substring(Math.max(a, b));

        listView.getItems().clear();

        for (String mid : replacements) {
            listView.getItems().add(prefix + mid + suffix);
        }

        // do not change anything about the modification
        return change;
    });
    textField.setTextFormatter(formatter);

    Scene scene = new Scene(new VBox(listView, textField));

    primaryStage.setScene(scene);
    primaryStage.show();
}

There are plenty more properies available including the text and carret and anchor positions before the change, see the javadoc.

fabian
  • 67,623
  • 12
  • 74
  • 102
0

Add listener to caretPositionProperty.

    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.scene.Scene;
    import javafx.scene.control.TextField;
    import javafx.stage.Stage;

    public class TextFieldCaretApp extends Application {

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

        @Override
        public void start(Stage stage) throws Exception {            
            TextField textField = new TextField();
            Scene scene = new Scene(textField);
            stage.setScene(scene);
            stage.show();

            textField.caretPositionProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
                System.out.println("caretPosition=" + newValue);
            });

            textField.textProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
                System.out.println("text=" + newValue);
            });
        }
    }
  • hi, since I need to update textfield inside textProperty listener, I need to retrieve caret position there. I tried nested listener already, but it's not working as expected. Thx! – ZihengCary Oct 24 '19 at 12:48