Многоразовые фрагменты FXML в JavaFX - PullRequest
0 голосов
/ 24 ноября 2018

Я реализую раздел с вкладками, где каждая вкладка будет содержать табличное представление.В этом табличном представлении есть подмножество столбцов, которые будут отображаться независимо от того, какая вкладка выбрана, но некоторые вкладки будут содержать дополнительные столбцы (обрабатываются программно).

По этим причинам каждая вкладка должна иметь отдельный контроллер, но мне было интересно, можно ли мне повторно использовать внутреннее содержимое вкладки FXML в каждой вкладке без необходимости копировать и вставлять код.Я думаю о том, как использовать компонент многократного использования, который я мог бы определить в другом файле FXML и просто включить в раздел вкладок.

В частности, я бы хотел, чтобы раздел содержимого в приведенном ниже коде находился в одном файле и просто ссылался на него в каждом файле, чтобы мне не пришлось вносить изменения в несколько файлов, если я хочу что-то изменитьв будущем.Я думаю, что это может быть достигнуто программно, но я бы предпочел решение FXML, если это возможно.

<Tab xmlns:fx="http://javafx.com/fxml/1"
     xmlns="http://javafx.com/javafx/8"
     fx:controller="com.SpecificController"
     id="specificTab" text="Specific Tab Name">

    <content>
        <JFXTreeTableView fx:id="commonTableView" VBox.vgrow="ALWAYS">
            <columns>
                <JFXTreeTableColumn fx:id="nameColumn" text="Name"/>
                <JFXTreeTableColumn fx:id="positionColumn" text="Position"/>
                <JFXTreeTableColumn fx:id="teamColumn" text="Team"/>
                <JFXTreeTableColumn fx:id="selectColumn" text="Select"/>
            </columns>
        </JFXTreeTableView>
    </content>
</Tab>

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

вы можете определить fxml в компонентной базе, используйте тег fxroot.

0 голосов
/ 24 ноября 2018

Я ни в коем случае не эксперт по JavaFX, но я смог придумать это решение.

Это MCVE, поэтому вы можете полностью воссоздать этот пример приложения и запустить его, чтобы увидеть его в действии..

В этом примере используется AnchorPane для многократно используемого узла FXML, но вы можете изменить его для использования Tab.Я считаю, что повторное использование самого контента немного проще.

Я использую простой Interface для определения наших контроллеров вкладок;это позволяет нам написать один метод, который устанавливает содержимое и отдельный контроллер для каждого Tab.


Main.java:

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

import java.io.IOException;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        try {
            // Load the main layout
            FXMLLoader loader = new FXMLLoader(getClass().getResource("MainLayout.fxml"));

            // Show the Stage
            primaryStage.setWidth(700);
            primaryStage.setHeight(500);
            primaryStage.setScene(new Scene(loader.load()));
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FXML документы:

MainLayout.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1"
            xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.reusableTabs.MainController">
    <VBox alignment="TOP_CENTER" prefHeight="400.0" prefWidth="600.0" spacing="10.0" AnchorPane.bottomAnchor="0.0"
          AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-size: 150%; -fx-font-weight: bold;" text="Reusable Tab Content Sample"/>
        <Separator prefWidth="200.0"/>
        <TabPane fx:id="tabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE"
                 VBox.vgrow="ALWAYS">
            <Tab fx:id="tab1" text="Tab #1"/>
            <Tab fx:id="tab2" text="Tab #2"/>
            <Tab fx:id="tab3" text="Tab #3"/>
        </TabPane>
    </VBox>
</AnchorPane>

TabContent.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
            prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="20.0" AnchorPane.bottomAnchor="0.0"
          AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <Label text="Look - reusable Tab contents!"/>
        <Button fx:id="btnTestController" mnemonicParsing="false" text="Test Controller"/>
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
    </VBox>
</AnchorPane>

Контроллеры:

MainController.java:

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

import java.io.IOException;

public class MainController {

    @FXML
    private TabPane tabPane;
    @FXML
    private Tab tab1;
    @FXML
    private Tab tab2;
    @FXML
    private Tab tab3;

    @FXML
    private void initialize() {

        // Our TabPane has 3 Tabs. Let's populate them with content, reusing our TabContent.fxml file
        setTabContent(tab1, new Tab1Controller());
        setTabContent(tab2, new Tab2Controller());
        setTabContent(tab3, new Tab3Controller());

    }

    /**
     * Sets the content of Tab to the TabContent.fxml document
     *
     * @param tab        The Tab whose content we wish to set
     * @param controller The controller for this particular Tab's content
     */
    private void setTabContent(Tab tab, TabController controller) {

        // Load our TabContent.fxml file and set it as the content of the Tab that was passed to this method
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("TabContent.fxml"));

            // Set the controller for this specific tab
            loader.setController(controller);

            // Set the content of the passed Tab to this FXML content
            tab.setContent(loader.load());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Tab1Controller:

import javafx.fxml.FXML;
import javafx.scene.control.Button;

public class Tab1Controller implements TabController {

    @FXML
    private Button btnTestController;

    @FXML
    private void initialize() {

        // Set our button to print out which controller is being used
        btnTestController.setOnAction(event -> System.out.println("Hello, from Controller #1!"));

    }
}

Просто дублируйте этот контроллер еще два раза для Tab2Controller.java и `Tab3Controller.java


Результат:

screenshot

При нажатии на кнопку Test Controller будет напечатано Hello, from Controller #2!, подтверждая, что содержимое каждой вкладкиуправляется собственным контроллером.

...