Выровняйте узлы внизу контейнера, затем центрируйте контейнер в сцене с JavaFX

Кажется, что строка 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, но это не имело никакого значения.

«Я пытаюсь создать гистограмму». Также обратите внимание, что технически это не гистограмма, а гистограмма.

James_D 21.08.2024 21:57
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Из документации для 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();
    }

}

Другие вопросы по теме