user18942691
user18942691

Reputation:

JavaFX: How to get rid of weird wrapping effect in expandable textarea?

hello iam facing a problem with my textarea. my goal is to make an expandable textarea which is just a normal textarea except it has no scrollbar, it wraps text and if the user wants to resize the width of the textarea the height needs to be updated.

everything works fine except one thing. lets say I already typed a paragraph into my textarea and then reduce the width of it just as much so that 1 or 2 letter are pushed in the next line because of wrapping then the height is not updating for some weird reason.

beofre i reduce width

after I reduced the width

iam not sure what iam doing wrong, do i use wrong listeners? or is there an problem with my text node? i would be very thankful if anyone can help me because iam sitting at this problem for days now.

here is my code:

@Override
public void start(Stage stage) throws IOException {

    VBox box = new VBox();
    TextArea area = new TextArea();

    area.setWrapText(true);

    area.setMinHeight(27);
    area.setPrefHeight(27);
    area.setMaxHeight(27);

    box.getChildren().add(area);

    Scene scene = new Scene(box);
    scene.getStylesheets().add(this.getClass().getResource("/gui/dumps/test.css").toExternalForm());

    stage.setScene(scene);
    stage.show();

    area.textProperty().addListener((obs, old, niu) -> {
        setHeight(area);
    });

    area.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
        setHeight(area);
    });
}

public void setHeight(TextArea area) {
    Text text = (Text) area.lookup(".text");

    double height = text.getLayoutBounds().getHeight() + 10;

    area.setMinHeight(height);
    area.setPrefHeight(height);
    area.setMaxHeight(height);
}

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

and my css stylesheet:

.text-area .scroll-pane {
-fx-hbar-policy: NEVER;
-fx-vbar-policy: NEVER;

}

Upvotes: 0

Views: 214

Answers (1)

Sai Dandem
Sai Dandem

Reputation: 9949

May be you can start with the below solution and see if you need any further changes.

The idea is to compute the height when the layoutChildren() of the TextArea is completed and then requesting the layout of TextArea to update to the computed height.

There may be other conditions you may need to consider, but I will leave that for you to work with.

enter image description here

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;

public class ResizableTextAreaDemo extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        VBox box = new VBox();
        TextArea area = new TextArea() {
            double insets;
            Node text;

            @Override
            protected void layoutChildren() {
                super.layoutChildren();
                // By this line, all the children layouts are computed.

                // Avoiding repetitive lookup calls.
                if (text == null) {
                    Region scrollPane = (Region) lookup(".scroll-pane");
                    Region content = (Region) lookup(".content");
                    double textAreaInsets = getInsets().getTop() + getInsets().getBottom();
                    double scrollInsets = scrollPane.getInsets().getTop() + scrollPane.getInsets().getBottom();
                    double contentInsets = content.getInsets().getTop() + content.getInsets().getBottom();
                    insets = textAreaInsets + scrollInsets + contentInsets;
                    text = lookup(".text");
                }

                // Compute the total height considering all the required insets.
                double totalHeight = insets + Math.ceil(text.getLayoutBounds().getHeight());
                setTextAreaHeight(this, totalHeight);

                // Finally, requesting layout of TextArea to resize to new value.
                requestLayout();
            }
        };
        area.setWrapText(true);
        box.getChildren().add(area);
        Scene scene = new Scene(box);
        stage.setScene(scene);
        stage.setTitle("TextArea Demo");
        stage.show();
    }

    public void setTextAreaHeight(TextArea area, double height) {
        area.setMinHeight(height);
        area.setPrefHeight(height);
        area.setMaxHeight(height);
    }

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

Upvotes: 3

Related Questions