JavaFX динамически изменяет размер окна в зависимости от количества элементов VBox

Я хочу создать служебный инструмент, который изменяет размер по вертикали, когда дети добавляются/удаляются из VBox. Дети изменяются посредством пользовательского ввода. Размер окна приложения не может быть изменен пользователем.

Я создал следующий файл FXML:

<AnchorPane fx:id = "rootPane" 
            maxHeight = "-Infinity" maxWidth = "-Infinity" 
            minHeight = "-Infinity" minWidth = "-Infinity" 
            prefHeight = "400.0" prefWidth = "600.0" 
            xmlns = "http://javafx.com/javafx/17.0.2-ea" 
            xmlns:fx = "http://javafx.com/fxml/1" 
            fx:controller = "myProject.controller.DynamicResizeController">
    <children>
        <VBox fx:id = "vBox" 
              layoutX = "148.0" layoutY = "144.0" 
              prefHeight = "200.0" prefWidth = "200.0">
            <children>
                <Label text = "This is a label" />
                <Button fx:id = "addButton" 
                        onAction = "#handleAddButtonClick" text = "Add Element" />
                <Button fx:id = "removeButton" 
                        text = "Remove Element" />
            </children>
        </VBox>
    </children>
</AnchorPane>

и класс контроллера:

public class DynamicResizeController {

    @FXML
    private VBox vBox;

    @FXML
    private AnchorPane rootPane;

    public void handleAddButtonClick(ActionEvent event) {
        Label label = new Label("New Element added!");
        vBox.getChildren().add(label);
        calculateAndResize();
    }

    private void calculateAndResize() {
        double totalHeight = 0;
        for (Node child : vBox.getChildren()) {
            totalHeight += child.prefHeight(-1) + child.getLayoutY();
        }

        resizeStage(totalHeight);
    }

    private void resizeStage(double height) {
        // set height of stage to height
    }

}

Основной класс довольно простой:

public class DynamicResizeApplication extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader(DynamicResizeApplication.class.getResource("view/dynamic-resize-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load());

        stage.setScene(scene);
        stage.initStyle(StageStyle.UNDECORATED);
        stage.show();
    }

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

}

Как мне установить высоту сцены? Я не нашел способа получить к нему доступ в классе контроллера.

Я не уверен, почему у вас есть панель привязки для корня и как вы собираетесь поступать с макетом, если добавляете больше дочерних элементов, чем может быть отображено на сцене. Возможно, вам следует использовать ListView или хотя бы добавить ScrollPane.

jewelsea 25.03.2024 08:42

Я не пробовал, но вам не нужно рассчитывать новую высоту сцены. Просто добавьте элементы в узел сцены и вызовите stage.sizeToScene(). Как только панель из вашего FXML добавлена ​​в окно, вы можете найти ее на этапе (Stage) mynode.getScene().getWindow(), где mynode — это некоторый @FXML аннотированный узел в контроллере.

jewelsea 25.03.2024 08:56

Посмотрите, может ли это помочь.

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

Ответы 1

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

+1 за то, что предложил @jewelsea. Действительно, вам нужно использовать метод sizeToScene(), чтобы вычисления выполнялись автоматически и изменяли размер окна.

Однако вызов sizeToScene() не всегда сделает ваше окно компактным по ширине его содержимого. Вам необходимо учитывать некоторые другие факторы, касающиеся того, как работает sizeToScene().

В первую очередь любые настройки prefWidth/prefHeight будут влиять на вычисления sizeToScene(). И наряду с этим играют роль настройки мин/макс.

Итак, мое предложение:

  • вам нужно просмотреть все узлы сцены, чтобы увидеть, какие настройки pref/min/max вам нужны. Удалите все объявления min/max/pref, если они вам не нужны.
  • Я знаю, что если вы сгенерируете fxml из SceneBuilder, вы получите все сгенерированные для вас атрибуты. Не поддавайтесь им!. Просмотрите каждый атрибут в FXML и удалите его, если он вам действительно не нужен (или вы о нем не знаете). Если он не работает должным образом, вы узнаете, какие атрибуты следует учитывать. (так вы научитесь)

Итак, что касается вашего вопроса: я не уверен, почему вы рассмотрели AnchorPane, но все настройки pref/min/max не требуются. По этой причине, даже если вы используете sizeToScene(), размер вашего окна не изменится.

Ниже приведена демонстрация и код fxml после удаления всех настроек размера и последующего вызова sizeToScene():

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<AnchorPane fx:id = "rootPane" xmlns = "http://javafx.com/javafx/17.0.2-ea" xmlns:fx = "http://javafx.com/fxml/1" fx:controller = "myProject.controller.DynamicResizeController">
    <children>
        <VBox fx:id = "vBox" layoutX = "148.0" layoutY = "144.0" >
            <children>
                <Label text = "This is a label" />
                <Button fx:id = "addButton" onAction = "#handleAddButtonClick" text = "Add Element" />
                <Button fx:id = "removeButton" text = "Remove Element" />
            </children>
        </VBox>
    </children>
</AnchorPane>

И код вашего контроллера:

public void handleAddButtonClick(ActionEvent event) {
  Label label = new Label("New Element added!");
  vBox.getChildren().add(label);
  vBox.getScene().getWindow().sizeToScene();
}

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