Show non-deletable text before input text in JavaFX text field
Asked Answered
W

1

8

I am currently trying to build an application which behaves similar to a command shell. I want to display a path that I give it (or a '>' character at the very least) before the user's input text in a javaFX text field. like this:

enter image description here

I have it so that the text field will clear when the user submits the text. After a submission it sets the text of the field to be my path to achieve a similar effect, but the user can still delete this path while inputting text.

How can I make it so that my path text appears in the field but the user cannot delete it?

I've tried this but it only updates the caret position after submission:

        textField.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            textField.positionCaret(textField.getLength());
        }
    });
Whose answered 28/6, 2017 at 8:53 Comment(2)
This should help: #19168250Cadent
@Oswald The answers to that question are pretty out-of-date, and don't include the currently-supported way of doing things like this, using a TextFormatter.Progress
P
8

You can use a TextFormatter to filter out invalid operations on the text field. A TextFormatter has a filter which filters changes to the text field; you can veto any changes by having the filter return null. The simplest implementation for what you describe would just filter out any changes where the caret position or the anchor for the text field were before the end of the fixed text:

UnaryOperator<TextFormatter.Change> filter = c -> {
    if (c.getCaretPosition() < prefix.length() || c.getAnchor() < prefix.length()) {
        return null ;
    } else {
        return c ;
    }
};

textField.setTextFormatter(new TextFormatter<String>(filter));

You can experiment with other logic here (for example if you want the user to be able to select the fixed text).

Here is a SSCCE:

import java.util.function.UnaryOperator;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TextFieldFixedPrefix extends Application {

    private TextField createFixedPrefixTextField(String prefix) {
        TextField textField = new TextField(prefix);

        UnaryOperator<TextFormatter.Change> filter = c -> {
            if (c.getCaretPosition() < prefix.length() || c.getAnchor() < prefix.length()) {
                return null ;
            } else {
                return c ;
            }
        };

        textField.setTextFormatter(new TextFormatter<String>(filter));

        textField.positionCaret(prefix.length());

        return textField ;
    }

    @Override
    public void start(Stage primaryStage) {

        TextField textField = createFixedPrefixTextField("/home/currentUser $ ");
        StackPane root = new StackPane(textField);
        Scene scene = new Scene(root, 300,40);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Progress answered 28/6, 2017 at 12:58 Comment(1)
And suppose we only want to allow numbers. How can we do that?Mainmast

© 2022 - 2024 — McMap. All rights reserved.