Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VBox .getHeight() Not Changing until after .setOnAction Finishes [duplicate]

Tags:

javafx

So I'm not sure how to calculate the height of the node during the .setOnAction event I have tried .requestLayout()/.applyCss() not sure what else to try I am trying to find the height of the vBox after adding a node but it is only printing the height of the node before the new one was added

public class Main extends Application {

    @Override
    public void start(Stage stage) {
        VBox vBoxContainer = new VBox();
        vBoxContainer.setAlignment(Pos.CENTER);
        vBoxContainer.setPrefSize(200,200);

        VBox vBox = new VBox();
        vBox.setAlignment(Pos.CENTER);
        for (int i = 0; i < 5; i++)
            vBox.getChildren().add(new Label("newLabel"));
        vBoxContainer.getChildren().add(vBox);

        Button button = new Button("Add Label");
        button.setOnAction(event -> {
            System.out.println("Height Before new Label:"+vBox.getHeight());
            vBox.getChildren().add(new Label("newLabel"));
            //here is where I was adding code to produce expected result
            System.out.println("Height After new Label:"+vBox.getHeight());
        });

        Button checkButton = new Button("Print VBox Height");
        checkButton.setOnAction(event -> System.out.println("VBox Height:"+vBox.getHeight()));

        vBoxContainer.getChildren().addAll(button, checkButton);

        stage.setScene(new Scene(vBoxContainer));
        stage.show();
    }
}

Run the example and Click the button that adds a Label to the vBox and it outputs

Actual Result:

Height Before new Label:85.0
Height After new Label:85.0

Expected Result:

Height Before new Label:85.0
Height After new Label:102.0    

But if you then click the Print VBox Height Button it will show the correct height of:

VBox Height:102.0
like image 771
Ghost Avatar asked Jan 26 '23 16:01

Ghost


2 Answers

requestLayout does not actually do a layout pass. It simply tells JavaFX, that a layout pass is required which will result in JavaFX doing the layout pass some time after your method returns. To do the layout yourself, you need to call layout yourself, i.e. change the logic in the event handler like this:

button.setOnAction(event -> {
    System.out.println("Height Before new Label:"+vBox.getHeight());
    vBox.getChildren().add(new Label("newLabel"));

    // manually doing layout on the root here
    vBoxContainer.applyCss();
    vBoxContainer.layout();

    System.out.println("Height After new Label:"+vBox.getHeight());
});

Note that I do the layout pass for the root, since the ancestor layouts can also be involved in determining the actual size of a Node...

like image 28
fabian Avatar answered Feb 04 '23 15:02

fabian


You can try adding a listener to the VBox's height property.

VBox vBoxContainer = new VBox();
vBoxContainer.setAlignment(Pos.CENTER);
vBoxContainer.setPrefSize(200, 200);

VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBoxContainer.getChildren().add(vBox);
vBox.heightProperty().addListener((observable, oldValue, newValue) -> {
    System.out.println("Height changed to: " + newValue.doubleValue());
    if(newValue.doubleValue() > 100)
    {
        //do something!
    }
});
for (int i = 0; i < 5; i++) {
    vBox.getChildren().add(new Label("newLabel"));
}
Button button = new Button("Add Label");
button.setOnAction(event -> {
    vBox.getChildren().add(new Label("newLabel"));
});
Button checkButton = new Button("Print VBox Height");
checkButton.setOnAction(event -> System.out.println("VBox Height:" + vBox.getHeight()));

vBoxContainer.getChildren().addAll(button, checkButton);
stage.setScene(new Scene(vBoxContainer));
stage.show();
like image 176
Sedrick Avatar answered Feb 04 '23 15:02

Sedrick