JavaFx: элемент вкладки не заполняет содержимое

У меня есть объявление TabPane следующим образом:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TabPane?>

<TabPane fx:id="rootNode" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" stylesheets="@dark_theme.css" tabClosingPolicy="UNAVAILABLE" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.AppController" />

И я хочу добавить вкладки с моего контроллера. Итак, я делаю:

    jsonConfig.getAvailableChannelIds().forEach( chId -> {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tab_item.fxml"));
            Tab item = fxmlLoader.load();
            item.setText(String.format("%d", chId));
            rootNode.getTabs().add(item);
        }catch (Exception e) {
            e.printStackTrace();
        }
    });

"tab_item.fxml" выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?>

<?import javafx.scene.layout.VBox?>
<Tab xmlns:fx="http://www.w3.org/1999/XSL/Transform">
   <VBox>
         <fx:include source="test.fxml"/>
   </VBox>
</Tab>

И, наконец, «test.fxml»:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: red;" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" />

И вот что у меня есть:

Чего мне не хватает, чтобы заполнить Tab контент красным квадратом?

минимальный воспроизводимый пример пожалуйста..
kleopatra 21.11.2022 14:57

Я предполагаю, что AnchorPane в test.fxml нужно maxHeight и maxWidth установить на Infinity.

SedJ601 21.11.2022 15:53

Вы явно устанавливаете предпочтительный размер 600 x 400. Что вы ожидаете, что произойдет /

James_D 21.11.2022 16:43

Не связано: это xmlns:fx="http://www.w3.org/1999/XSL/Transform" не является пространством имен для FXML. Предоставленное вами пространство имен XML предназначено для XSL-преобразований, которые вообще не используются в вашем документе. Вместо этого используйте xmlns:fx="http://javafx.com/fxml". Пространство имен в этом случае важно только для проверки XML (которую вы не используете) и для помощи инструментам, таким как IDE, для улучшения помощи при редактировании.

jewelsea 22.11.2022 00:50

@SedJ601, к сожалению, имея этот <AnchorPane maxHeight="Infinity" maxWidth="Infinity" minHeight="-Infinity" minWidth="-Infinity" style="-fx-background-color: red;" xmlns="javafx.com/javafx/19 " xmlns:fx=" javafx.com/fxml/1" /> приводит к тому, что элемент не отображается на сцене. Есть идеи?

Dmitry 22.11.2022 20:05

Вы избавились от prefHeight="400.0" prefWidth="600.0", как предложил @James_D?

SedJ601 23.11.2022 00:39

@ SedJ601 SedJ601 да, я избавился от него, но ключевым моментом здесь является наличие AnchorPane в качестве содержимого для Tab. При первоначальном использовании подхода VBox удаление prefs приводит к тому, что элемент не отображается.

Dmitry 23.11.2022 07:18

Если вы также избавитесь от минимального и максимального размеров, чтобы панель привязки могла расти, вы можете затем указать VBox, чтобы панель привязки в test.fxml увеличивалась настолько, насколько она хочет, используя обычные настройки VBox. Я не совсем понимаю, почему у вас вообще есть VBox.

James_D 23.11.2022 15:34
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
2
8
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Итак, я нашел по крайней мере обходной путь здесь -> просто оберните fx:include с помощью AnchorsPane, и он работает:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?>

<?import javafx.scene.layout.AnchorPane?>
<Tab xmlns:fx="http://www.w3.org/1999/XSL/Transform">
   <content>
       <AnchorPane>
            <fx:include source="test.fxml" AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0"/>
       </AnchorPane>
   </content>
</Tab>
 

Ваше решение явно установить размер pref на то, что вам не нужно, состоит в том, чтобы найти обходной путь, который заставляет игнорировать размер pref????

James_D 21.11.2022 16:44

@James_D, а что вы предлагаете, кроме того, что вы немного высокомерны в своем комментарии? Если я где-то ошибаюсь, не могли бы вы указать это прямо, если это возможно?

Dmitry 22.11.2022 20:07

Не указывайте предпочтительный размер явно.

James_D 23.11.2022 01:48

@James_D, как я вижу, этого недостаточно, если я останусь с VBox, я вообще ничего не увижу. Таким образом, ключевым моментом здесь является использование AnchorPane в качестве содержимого для элемента Tab.

Dmitry 23.11.2022 07:20

У вас также явно установлен максимальный размер USE_PREF_SIZE (-Infinity). Избавьтесь от всего этого, и вы сможете использовать настройки макета естественным образом. Почему вам все равно нужно обернуть содержимое вкладки в панель?

James_D 23.11.2022 16:20
Ответ принят как подходящий

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

Я рекомендую прочитать старый учебник по верстке Oracle . Он был написан давным-давно (до Java 8), поэтому стиль кода немного устарел, но все концепции компоновки по-прежнему актуальны. Также прочтите Javadocs для пакета макета, и, вероятно, вы уже читали Javadocs для любого компонента макета, который вы используете (если нет, вам всегда следует читать документы для используемых вами классов).

У тебя есть

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" 
            minHeight="-Infinity" minWidth="-Infinity" 
            prefHeight="400.0" prefWidth="600.0" 
            style="-fx-background-color: red;"
            xmlns="http://javafx.com/javafx/19" 
            xmlns:fx="http://javafx.com/fxml/1" />

который явно устанавливает предпочтительный размер на 600x400 пикселей, а также устанавливает минимальный и максимальный размеры на -Infinity, что является контрольным значением Region.USE_PREF_SIZE. Поэтому VBox всегда будет изменять размер содержимого до 600x400 пикселей (если для этого достаточно места в VBox).

Удалите все эти настройки (я также исправил пространство имен, хотя оно вам здесь действительно не нужно):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane style="-fx-background-color: red;"
            xmlns:fx="http://javafx.com/fxml" />

Теперь VBox по-прежнему будет пытаться установить предпочтительный размер содержимого, который по умолчанию вычисляется из собственного содержимого. Поскольку панель привязки пуста, предпочтительный размер будет вычисляться как 0x0. Однако, поскольку максимальный размер теперь не ограничен, вы можете указать VBox, чтобы он увеличивался:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?>

<?import javafx.scene.layout.VBox?>
<Tab xmlns:fx="http://javafx.com/fxml/">
        <VBox fillWidth="true">
        <fx:include source="test.fxml" VBox.vgrow="ALWAYS" />
        </VBox>
</Tab>

Теперь содержимое, определенное в test.fxml, заполнит VBox. Поведение Tab заключается в том, чтобы позволить его содержимому заполнить всю область вкладки, поэтому VBox заполнит вкладку.

Конечно, не совсем понятно, почему вы вообще заворачиваете test.fxml в VBox. Поскольку вкладка будет заполнена своим содержимым по умолчанию, почему бы просто не упростить

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?>

<Tab xmlns:fx="http://javafx.com/fxml/">
        <fx:include source="test.fxml" />
</Tab>

Вот полный пример, в котором удалены все ненужные жестко заданные размеры и лишние панели макета:

HelloApplication.java:

package org.jamesd.examples.tab;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 320, 240);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

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

hello-view.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TabPane?>

<TabPane fx:id="rootNode"
         tabClosingPolicy="UNAVAILABLE"
         xmlns:fx="http://javafx.com/fxml/"
         fx:controller="org.jamesd.examples.tab.AppController" />

AppController.java:

package org.jamesd.examples.tab;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;

public class AppController {

    @FXML
    private TabPane rootNode ;

    public void initialize() {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tab_item.fxml"));
            Tab item = fxmlLoader.load();
            item.setText(String.format("%d", 42));
            rootNode.getTabs().add(item);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

tab-item.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?>

<Tab xmlns:fx="http://javafx.com/fxml/">
        <fx:include source="test.fxml" />
</Tab>

и test.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane style="-fx-background-color: red;"/>

спасибо за подробное объяснение и ссылки на документы - теперь у меня есть картинка

Dmitry 23.11.2022 17:25

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