The line vbox.setAlignment(Pos.BOTTOM_CENTER) appears to override stackpane's ability to lay out nodes in the center of the scene.
I'm trying to create a bar chart (of letters in a .txt doc), so I need the bars to grow from the bottom of their container (a vbox). I put the vbox in an hbox, and I want the hbox centered in the scene. I thought putting the hbox in a stackpane would center it, but instead it sets at the bottom center of the scene (so stackpane has no effect).
`// Previous code containing arrays letterCount[] & alphabet[]
HBox hbox = new HBox();
hbox.setSpacing(5);
hbox.setAlignment(Pos.CENTER); //Centers hbox at the bottom, not the middle??
for (int i=0; i<26; i++) {
Rectangle bar = new Rectangle(10, letterCount[i]);
bar.setStroke(Color.BLACK);
bar.setFill(Color.TRANSPARENT);
Label label = new Label(String.valueOf(alphabet[i]));
VBox vbox = new VBox(5);
vbox.setAlignment(Pos.BOTTOM_CENTER); // THIS OVERRIDES STACKPANE??
vbox.getChildren().addAll(bar, label);
hbox.getChildren().add(vbox);
}
StackPane sp = new StackPane(hbox);
sp.setAlignment(Pos.CENTER);
Scene scene = new Scene(sp, 500, 500);
// etc.`
NOTE: I tried using VBox.setVgrow(bar, Priority.ALWAYS) instead of setting vbox's alignment to Pos.BOTTOM_CENTER, but it didn't make any difference.
From the documentation for StackPane
:
The stackpane will attempt to resize each child to fill its content area. If the child could not be sized to fill the stackpane (either because it was not resizable or its max size prevented it) then it will be aligned within the area using the alignment property
and from the documentation for HBox
, the maximum height of an HBox
is Double.MAX_VALUE
.
Consequently, the HBox
fills the entire stack pane.
Similarly, the VBox
s will fill the entire height of the HBox
(which is the height of the StackPane
), and since they align their content at the bottom, everything appears at the bottom of the stack pane.
Try limiting the maximum height of the HBox
to be the preferred height:
hbox.setMaxHeight(Region.USE_PREF_SIZE);
Here is a complete working example:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Random;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
String[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
Random rng = new Random();
int[] letterCount = new int[alphabet.length];
for (int i = 0 ; i < letterCount.length; i++) letterCount[i] = rng.nextInt(200);
HBox hbox = new HBox();
hbox.setSpacing(5);
hbox.setAlignment(Pos.CENTER);
hbox.setMaxHeight(Region.USE_PREF_SIZE);
for (int i=0; i< alphabet.length; i++) {
Rectangle bar = new Rectangle(10, letterCount[i]);
bar.setStroke(Color.BLACK);
bar.setFill(Color.TRANSPARENT);
Label label = new Label(String.valueOf(alphabet[i]));
VBox vbox = new VBox(5);
vbox.setAlignment(Pos.BOTTOM_CENTER);
vbox.getChildren().addAll(bar, label);
hbox.getChildren().add(vbox);
}
StackPane sp = new StackPane(hbox);
sp.setAlignment(Pos.CENTER);
Scene scene = new Scene(sp, 500, 500);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
which produces the desired results:
There are various other options. E.g. calling
hbox.setAlignment(Pos.BOTTOM_CENTER);
hbox.setFillHeight(false);
hbox.setMaxHeight(Region.USE_PREF_SIZE);
will prevent the VBox
s from growing beyond their preferred size, and position them at the bottom (horizontally centered) of the HBox
. Then you can omit setting the alignment on the VBox
(since the VBox
will be just big enough to hold its content, so it won't be able to align anything anyway).