Marc Rasmussen
Marc Rasmussen

Reputation: 20555

Javafx textfield resize to text length?

Hello guys I am building a chat server where I use a textfield on the screen to type in the chat message that the user writes, the idea is that it works like a bubble over a persons head when he types a message.

my question is in order to not make a textbox that is too large or too small is there a way to make the textbox resize (trim if you will) so it adjust to the text written in the textfield?

P.S. I'm using JavaFx scenebuilder to do all of this.

Upvotes: 8

Views: 36146

Answers (6)

Jerry H.
Jerry H.

Reputation: 409

The best / easiest way to do this is to use JavaFX's "USE_COMPUTED_SIZE" option. You can either define it in the FXML, or programatically like this:

TextField textField = new TextField("hello");
textField.setPrefWidth(Control.USE_COMPUTED_SIZE);

Upvotes: 0

Mohammad Hassany
Mohammad Hassany

Reputation: 983

You can use computeTextWidth method in the com.sun.javafx.scene.control.skin.Utils. the method is used in javafx.scene.control.Label class to calculate the minimum width for label content.

I solved my problem as below:

field.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> ob, String o,
                String n) {
            // expand the textfield
            field.setPrefWidth(TextUtils.computeTextWidth(field.getFont(),
                    field.getText(), 0.0D) + 10);
        }
    });

I have added a listener to textProperty, and with every text change i change the prefWidth of textfield.

Note: as long as the Utils.computeTextWidth() is not public, I have copied the source code to a new class (TextUtils).

Here is the full source code:

package me.jone30rw.fxcontrol;

import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;

public class TextUtils {

    static final Text helper;
    static final double DEFAULT_WRAPPING_WIDTH;
    static final double DEFAULT_LINE_SPACING;
    static final String DEFAULT_TEXT;
    static final TextBoundsType DEFAULT_BOUNDS_TYPE;
    static {
        helper = new Text();
        DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
        DEFAULT_LINE_SPACING = helper.getLineSpacing();
        DEFAULT_TEXT = helper.getText();
        DEFAULT_BOUNDS_TYPE = helper.getBoundsType();
    }

    public static double computeTextWidth(Font font, String text, double help0) {
        // Toolkit.getToolkit().getFontLoader().computeStringWidth(field.getText(),
        // field.getFont());

        helper.setText(text);
        helper.setFont(font);

        helper.setWrappingWidth(0.0D);
        helper.setLineSpacing(0.0D);
        double d = Math.min(helper.prefWidth(-1.0D), help0);
        helper.setWrappingWidth((int) Math.ceil(d));
        d = Math.ceil(helper.getLayoutBounds().getWidth());

        helper.setWrappingWidth(DEFAULT_WRAPPING_WIDTH);
        helper.setLineSpacing(DEFAULT_LINE_SPACING);
        helper.setText(DEFAULT_TEXT);
        return d;
    }
}

Upvotes: 21

Emily L.
Emily L.

Reputation: 5931

Since JavaFX 8, this is by far the simplest:

textField.prefColumnCountProperty().bind(textField.textProperty().length());

Upvotes: 8

adekcz
adekcz

Reputation: 410

No font dependent magic required if you use setPrefColumnCount

        tf.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ob, String o, String n) {
                tf.setPrefColumnCount(tf.getText().length() +1);
            }
        });

Upvotes: 3

Kalaschni
Kalaschni

Reputation: 2428

In JavaFX 8, there is a solution for that, here is the code:

TextField tf = new TextField();
// Set Max and Min Width to PREF_SIZE so that the TextField is always PREF
tf.setMinWidth(Region.USE_PREF_SIZE);
tf.setMaxWidth(Region.USE_PREF_SIZE);
tf.textProperty().addListener((ov, prevText, currText) -> {
    // Do this in a Platform.runLater because of Textfield has no padding at first time and so on
    Platform.runLater(() -> {
        Text text = new Text(currText);
        text.setFont(tf.getFont()); // Set the same font, so the size is the same
        double width = text.getLayoutBounds().getWidth() // This big is the Text in the TextField
                + tf.getPadding().getLeft() + tf.getPadding().getRight() // Add the padding of the TextField
                + 2d; // Add some spacing
        tf.setPrefWidth(width); // Set the width
        tf.positionCaret(tf.getCaretPosition()); // If you remove this line, it flashes a little bit
    });
});
tf.setText("Hello World!");
  • In JavaFX 2.2 this code works with little limitations. You can't set the Font(so if you do not use the std-font, you must set it manually).
  • You can't get the padding from a TextField(so if you know the padding, write it hardcoded).

Happy Coding,
Kalasch

Upvotes: 11

Uluk Biy
Uluk Biy

Reputation: 49185

It is time to do some coding behind the scenes(builder) :).
The following code chunk is not a neat solution but better than none. :)

// define width limits
textField.setMinWidth(50);
textField.setPrefWidth(50);
textField.setMaxWidth(400);
// add listner
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        textField.setPrefWidth(textField.getText().length() * 7); // why 7? Totally trial number.
    }
});

Upvotes: 4

Related Questions