Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show non-deletable text before input text in JavaFX text field

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());
        }
    });
like image 293
Matt Haidet Avatar asked Jun 28 '17 08:06

Matt Haidet


1 Answers

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);
    }
}
like image 76
James_D Avatar answered Nov 13 '22 23:11

James_D