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!
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.
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();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With