Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto-expand TextField to fit text

Tags:

java

javafx

I want to create a text field that expands horizontally as more text is entered.

After binding the prefColumnCount property to the length of the text in the TextField, its size increases as text gets longer. However, the caret's position is not updated and it gets stuck at the same place, no matter the text length. The user has to manually move the caret to the front in order for it to be displayed properly.

Images:

What it looks like after inputting some text, the text doesn't occupy the whole text field:

After moving the caret at the beginning of the text:

Here is my current code:

TextField textField = new TextField();
textField.prefColumnCountProperty().bind(textField.textProperty().length());
setHgrow(textField, Priority.ALWAYS);

How do I fix this problem? Any help is appreciated!

like image 411
Diamond Block Avatar asked Sep 05 '19 21:09

Diamond Block


1 Answers

This example uses a separate measuring text variable in its own css styled scene to calculate updates to the preferred size of the TextField so that it's preferred size expands and shrinks as required.

short text

long text

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.TextField;
import javafx.scene.layout.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class MagicExpander extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        TextField textField = new ExpandingTextField();

        Pane layout = new VBox(textField);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout, 600, 40));
        stage.show();
    }

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

    static class ExpandingTextField extends TextField {
        private static int MAGIC_PADDING = 20;

        private Text measuringText = new Text();
        // To allow potential css formatting to work for the text,
        // it is required that text be placed in a Scene,
        // even though we never explicitly use the scene.
        private Scene measuringScene = new Scene(new Group(measuringText));

        ExpandingTextField() {
            super();
            setPrefWidth(MAGIC_PADDING);
            setMinWidth(MAGIC_PADDING);
            setMaxWidth(USE_PREF_SIZE);

            // note if the text in your text field is styled, then you should also apply the
            // a similar style to the measuring text here if you want to get an accurate measurement.

            textProperty().addListener(observable -> {
                measuringText.setText(getText());
                setPrefWidth(measureTextWidth(measuringText) + MAGIC_PADDING);
            });
        }

        private double measureTextWidth(Text text) {
            text.applyCss();
            return text.getLayoutBounds().getWidth();
        }
    }
}
like image 199
jewelsea Avatar answered Sep 29 '22 11:09

jewelsea