Closed PavelTurk closed 2 months ago
Not sure if this will work but let's start with just this:
var messageArea = new InlineCssTextArea();
messageArea.setPrefWidth(500);
messageArea.setMinWidth(500);
messageArea.setMaxWidth(500);
messageArea.setAutoHeight(true);
// add text to it with styles
So no scrollpane and no height property listener. If this doesn't work as you would like then we'll build on it.
@Jugen Thank you very much for your help. I have two problems with the code you provided. This is the first problem. Code:
public class JavaFxTest extends Application {
@Override
public void start(Stage primaryStage) {
var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lacinia, elit in bibendum tempor, purus dolor venenatis arcu, vitae congue dolor dui non tellus. Sed iaculis et risus sed scelerisque. Pellentesque id nibh sit amet magna molestie mollis in pharetra nunc. Suspendisse vitae pretium lacus. Fusce consectetur quam ac ante gravida gravida. Aenean nunc justo, vestibulum quis libero eget, semper condimentum turpis. Phasellus suscipit aliquam libero sit amet viverra. Fusce semper tempus lorem, at facilisis ante lacinia non.";
var messageArea = new InlineCssTextArea();
messageArea.setWrapText(true);
messageArea.setEditable(false);
messageArea.setPrefWidth(500);
messageArea.setMinWidth(500);
messageArea.setMaxWidth(500);
messageArea.setAutoHeight(true);
messageArea.appendText(text);
var root = new VBox(messageArea);
root.setStyle("-fx-background-color: red");
var scene = new Scene(root, 600, 200);
primaryStage.setTitle("JavaFX Test");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you run this code, and after that click on text area you will see that autoheight is not very accurate:
Or I do something wrong?
This is the second problem. It seems that when autoHeight is used then getHeight() returns wrong value in PostLayoutPulseListener. This is my code:
public class JavaFxTest extends Application {
private boolean pulsePassed = false;
@Override
public void start(Stage primaryStage) {
var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lacinia, elit in bibendum tempor, purus dolor venenatis arcu, vitae congue dolor dui non tellus. Sed iaculis et risus sed scelerisque. Pellentesque id nibh sit amet magna molestie mollis in pharetra nunc. Suspendisse vitae pretium lacus. Fusce consectetur quam ac ante gravida gravida. Aenean nunc justo, vestibulum quis libero eget, semper condimentum turpis. Phasellus suscipit aliquam libero sit amet viverra. Fusce semper tempus lorem, at facilisis ante lacinia non.";
var root = new StackPane();
root.setStyle("-fx-background-color: red");
var button = new Button("Push Me");
root.getChildren().add(button);
var scene = new Scene(root, 600, 400);
primaryStage.setTitle("JavaFX Test");
primaryStage.setScene(scene);
primaryStage.show();
button.setOnAction(e -> {
var messageArea = new InlineCssTextArea();
messageArea.setWrapText(true);
messageArea.setEditable(false);
messageArea.setPrefWidth(500);
messageArea.setMinWidth(500);
messageArea.setMaxWidth(500);
messageArea.setAutoHeight(true);
messageArea.appendText(text);
var label = new Label(text);
label.setWrapText(true);
label.setStyle("-fx-background-color: cyan");
label.setPrefWidth(500);
label.setMinWidth(500);
label.setMaxWidth(500);
var box = new VBox(messageArea, label);
box.sceneProperty().addListener((ov, oldV, newV) -> {
if (newV != null) {
newV.addPostLayoutPulseListener(() -> {
if (!pulsePassed) {
this.pulsePassed = true;
System.out.println("TextArea height:" + messageArea.getHeight());
System.out.println("Label height:" + label.getHeight());
}
});
}
});
root.getChildren().add(new Pane(box));
});
}
public static void main(String[] args) {
launch(args);
}
}
This is output:
TextArea height:100.0
Label height:128.0
And these are real sizes:
As you see textArea height is about 120 pixels (but not 100). At the same time label height it correct - 128 pixels.
With your first code provided above I see what you mean in video but can't replicate on my system ?
With the 2nd code I get the same "result" as you. It seems that the TextArea height requires another pulse to calculate correctly.
If you change pulsePassed
to an int and increment it, printing to console when it reaches 1 or 2 then it'll be correct.
This maybe explains the flicker ?
@Jugen About the first problem - I will try to run it on windows and play with font-size. BTW - maybe you could install virtual box with linux? It is very easy ... when it works :). There are also building problems on linux that we discussed.
About the second problem, yes, it can explain the flicker. But is it possible to make TextArea calculate height in the first pulse? Or is it impossible? I am asking because Every time a pulse occurs, this listener will be called on the JavaFX Application Thread directly after the CSS and layout passes, but before any rendering is done for this frame.
so, it is normally to expect that when pulse listener is called all sizes must be already calculated (as I understand this javadoc).
It seems that the delay only happens the first time the TextArea is rendered. This is because for the height to be calculated the width needs to known, so if the width is zero then a layout request is issued first to determine the width and this then results in the height only being calculated on the 2nd pass.
@Jugen But we do set width : messageArea.setPrefWidth(500); messageArea.setMinWidth(500); messageArea.setMaxWidth(500);
. And yes, it seems to happen the first time the TextArea is rendered. However, for my application it is a problem as I plan to use TextArea in dialogs and popups.
Hmm, the TextArea requires its actual width. Those methods just specify the width limits and preference, not it's final rendered width which will depend on other things as well like the parent containers it is in.
You can try the following hack to prepare the messageArea for dialogs and popups:
// Dummy scene to trigger initial layout to set width to 500
new Scene( messageArea, 500, 50 ).snapshot( null );
messageArea.appendText( text ); // Must be after
// Add messageArea to the Dialog/Popup container
@Jugen Can we add something like messageArea.setAutoHeight(true, 500);
where 500 is the supposed real width? If I provide correct width, then I get correct height, if wrong, that's my fault.
@Jugen Or messageArea.setAutoHeight(true, usePrefWidthForCalculation);
Have submitted a PR that calculates the height using the preferred width when appropriate as suggested. Also updated latest maven snapshot including this PR. Please assess and provide feedback, thanks.
@Jugen I checked maven snapshot for the tests of both problems. Everything seems to work:
with output:
TextArea height:135.0
Label height:128.0
Thank you very much for your help.
Let's assume there is an unknown text with some styles.
Now, I need
As it is seen the problem is that I need whole document height when I only add text area to scene. I tried this code:
This code works, but the problem is that when messageArea becomes visible it has one height and later its height is changed and user sees
flickering
. I tried to addBut it didn't help. Could anyone say how to do it if it is possible?