Кажется, что строка vbox.setAlignment(Pos.BOTTOM_CENTER) переопределяет способность stackpane размещать узлы в центре сцены.
Я пытаюсь создать гистограмму (букв в документе .txt), поэтому мне нужно, чтобы столбцы росли из нижней части контейнера (vbox). Я помещаю vbox в hbox и хочу, чтобы hbox располагался по центру сцены. Я думал, что размещение hbox в стековой панели центрирует его, но вместо этого он устанавливается в нижней части сцены (поэтому стековая панель не имеет никакого эффекта).
`// 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.`
ПРИМЕЧАНИЕ. Я попробовал использовать VBox.setVgrow(bar, Priority.ALWAYS) вместо установки выравнивания vbox на Pos.BOTTOM_CENTER, но это не имело никакого значения.
Из документации для StackPane:
Stackpane попытается изменить размер каждого дочернего элемента, чтобы заполнить его область содержимого. Если размер дочернего элемента не может быть изменен для заполнения стековой панели (либо потому, что его размер не изменялся, либо его максимальный размер препятствовал этому), тогда он будет выровнен внутри области с использованием свойства выравнивания.
а из документации для HBox максимальная высота HBox
равна Double.MAX_VALUE
.
Следовательно, HBox
заполняет всю панель стека.
Аналогично, VBox
заполнят всю высоту HBox
(которая равна высоте StackPane
), и поскольку они выравнивают свое содержимое внизу, все отображается внизу панели стека.
Попробуйте ограничить максимальную высоту HBox
так, чтобы она была предпочтительной:
hbox.setMaxHeight(Region.USE_PREF_SIZE);
Вот полный рабочий пример:
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();
}
}
который дает желаемые результаты:
Есть и другие варианты. Например. звоню
hbox.setAlignment(Pos.BOTTOM_CENTER);
hbox.setFillHeight(false);
hbox.setMaxHeight(Region.USE_PREF_SIZE);
предотвратит рост VBox
за пределы желаемого размера и расположит их внизу (по горизонтали по центру) HBox
. Тогда вы можете не устанавливать выравнивание для VBox
(поскольку VBox
будет достаточно большим, чтобы вместить его содержимое, поэтому он все равно не сможет ничего выровнять).
Вместо того, чтобы напрямую отображать диаграмму в вашем коде, вы можете разместить BarChart с (при необходимости) настроенным prefSize в вашем StackPane
(именно это и делает это решение).
Чтобы исправить размер диаграммы, я обернул ее Group
, но вы можете пропустить это, если хотите, чтобы размер диаграммы можно было изменять.
К диаграмме добавляется фиолетовая рамка, указывающая протяженность границ диаграммы.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
public class LettergramApp extends Application {
@Override
public void start(Stage stage) throws IOException {
String[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
XYChart.Series<String, Number> series = new XYChart.Series<>();
for (String s : alphabet) {
series.getData().add(
new XYChart.Data<>(
s,
ThreadLocalRandom.current().nextInt(
50, 200
)
)
);
}
BarChart<String, Number> barChart = new BarChart<>(
new CategoryAxis(FXCollections.observableArrayList(alphabet)),
new NumberAxis(0, 200, 20)
);
barChart.getData().add(series);
barChart.setLegendVisible(false);
barChart.setPrefSize(800, 500);
barChart.setStyle("-fx-border-color: purple;");
StackPane layout = new StackPane(new Group(barChart));
Scene scene = new Scene(layout, 900, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
«Я пытаюсь создать гистограмму». Также обратите внимание, что технически это не гистограмма, а гистограмма.