Matthew Wright
Matthew Wright

Reputation: 1525

JavaFX Node will not grow in height despite constraints when buried within several panes

I've been struggling with this issue for a couple hours and managed to reproduce the problem with the sample below. The actual program changes what is set in main.add(node, 0, 1) as the content based on what button is pressed in menu. I tried several different things such as AnchorPanes, changing setMaxHeight, and setVgrow for many different nodes in the each pane but have not been very successful. How would I make the ListView in the example fill the rest of the window height where it is located?

public class Main extends Application {

    public void start(Stage stage) throws Exception {
        // I've tried with this as a VBox, no effect.
        GridPane main = new GridPane();
        main.setGridLinesVisible(true);
        main.setHgap(5);
        main.setVgap(10);

        // Meant to change what content is displayed in the actual program.
        HBox menu = new HBox();
        menu.setMaxWidth(Double.MAX_VALUE);
        menu.setAlignment(Pos.CENTER);
        main.add(menu, 0, 0);
        GridPane.setHgrow(menu, Priority.ALWAYS);
        menu.getChildren().addAll(new Button("Button 1"), new Button("Button 2"), new Button("Button 3"), new Label("Hello world!"));

        // Changes often.
        GridPane content = new GridPane();
        main.add(content, 0, 1);

        // Options for the displayed content, changes the StackPane displayed below in my actual program.
        HBox submenu = new HBox();
        submenu.setMaxWidth(Double.MAX_VALUE);
        submenu.setAlignment(Pos.CENTER);
        content.add(submenu, 0, 0);
        GridPane.setHgrow(submenu, Priority.ALWAYS);
        submenu.getChildren().addAll(new Button("Button A"), new Button("Button B"), new Button("Button C"), new Label("Hello world!"));

        // This is a custom class extended by StackPane in my actual program. Is often over overlayed with another transparent StackPane (not relevant to the problem).
        StackPane subcontent = new StackPane();
        subcontent.setMaxHeight(Double.MAX_VALUE);
        subcontent.setMaxWidth(Double.MAX_VALUE);
        content.add(subcontent, 0, 1);

        // This was meant to be a TabPane in my actual program but this has the same outcome that won't fill the rest of the window height.
        ListView<String> list = new ListView<>();
        list.setMaxHeight(Double.MAX_VALUE);
        list.setMaxWidth(Double.MAX_VALUE);
        ObservableList<String> items = FXCollections.observableArrayList();
        list.setItems(items);

        subcontent.getChildren().add(list);

        for(int i=0; i<100; i++) {
            items.add("# "+i);
        }

        Scene scene = new Scene(main, 900, 550);
        stage.setScene(scene);
        stage.show();
    }

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

Upvotes: 1

Views: 2037

Answers (1)

James_D
James_D

Reputation: 209235

You need both

GridPane.setVgrow(content, Priority.ALWAYS);

and

GridPane.setVgrow(subcontent, Priority.ALWAYS);

The grid panes are going to size things to their preferred heights with the default vgrow: the preferred height of content is determined by the preferred height(s) of its child nodes, and the preferred height of a ListView is a fixed (arbitrary) size (I believe 400 pixels). So if you don't instruct subcontent to grow, it will by the preferred size of the list view, and forcing content to grow will just add extra (blank) space to content: if you don't force content to grow, it will take its preferred size, which is the preferred size of subcontent plus the preferred size of submenu.

Setting the max height doesn't do anything in this example, as you just need to allow the various nodes to grow beyond their preferred size:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    public void start(Stage stage) throws Exception {
        // I've tried with this as a VBox, no effect.
        GridPane main = new GridPane();
        main.setGridLinesVisible(true);
        main.setHgap(5);
        main.setVgap(10);

        // Meant to change what content is displayed in the actual program.
        HBox menu = new HBox();
//        menu.setMaxWidth(Double.MAX_VALUE);
        menu.setAlignment(Pos.CENTER);
        main.add(menu, 0, 0);
        GridPane.setHgrow(menu, Priority.ALWAYS);
        menu.getChildren().addAll(new Button("Button 1"), new Button("Button 2"), new Button("Button 3"), new Label("Hello world!"));

        // Changes often.
        GridPane content = new GridPane();
        main.add(content, 0, 1);

        // Options for the displayed content, changes the StackPane displayed below in my actual program.
        HBox submenu = new HBox();
//        submenu.setMaxWidth(Double.MAX_VALUE);
        submenu.setAlignment(Pos.CENTER);
        content.add(submenu, 0, 0);
        GridPane.setHgrow(submenu, Priority.ALWAYS);
        submenu.getChildren().addAll(new Button("Button A"), new Button("Button B"), new Button("Button C"), new Label("Hello world!"));

        // This is a custom class extended by StackPane in my actual program. Is often over overlayed with another transparent StackPane (not relevant to the problem).
        StackPane subcontent = new StackPane();
//        subcontent.setMaxHeight(Double.MAX_VALUE);
//        subcontent.setMaxWidth(Double.MAX_VALUE);
        content.add(subcontent, 0, 1);


        // This was meant to be a TabPane in my actual program but this has the same outcome that won't fill the rest of the window height.
        ListView<String> list = new ListView<>();
//        list.setMaxHeight(Double.MAX_VALUE);
//        list.setMaxWidth(Double.MAX_VALUE);
        ObservableList<String> items = FXCollections.observableArrayList();
        list.setItems(items);

        subcontent.getChildren().add(list);

        for(int i=0; i<100; i++) {
            items.add("# "+i);
        }

        GridPane.setVgrow(content, Priority.ALWAYS);
        GridPane.setVgrow(subcontent, Priority.ALWAYS);


        Scene scene = new Scene(main, 900, 550);
        stage.setScene(scene);
        stage.show();

    }

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

Upvotes: 2

Related Questions