【问题标题】:JavaFX Reusable FXML SnippetsJavaFX 可重用的 FXML 片段
【发布时间】:2018-11-23 22:46:58
【问题描述】:

我正在实现一个选项卡部分,其中每个选项卡都包含一个表格视图。在此表视图中,无论选择哪个选项卡,都会呈现列的子集,但某些选项卡将包含其他列(以编程方式处理)。

由于这些原因,每个选项卡都需要有一个单独的控制器,但我想知道是否可以在每个选项卡中重用选项卡 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>

【问题讨论】:

  • 使用实际代码非常简单。不过,你激起了我的兴趣,我会看看我能在 FXML 中想出什么。

标签: java javafx fxml


【解决方案1】:

我绝不是 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


结果:

点击Test Controller按钮会打印出Hello, from Controller #2!,确认每个Tab的内容都由各自的控制器控制。

【讨论】:

  • 谢谢!你是对的,在我的特定用例中,我可能会选择使用内容的可读性,如果我需要更改内容,我只需要经历额外 20 分钟的重构......但在更大的应用程序中,这个如果完全通过代码来做这件事是不可能的,那将是一个更好的选择。我想我正在寻找一些简单的东西,类似于在 React 中完成事情的方式......但我想这对 JavaFX 的要求有点太多了!再次感谢伙计!
【解决方案2】:

您可以在组件库中定义一个 fxml,使用 fxroot 标签。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 2014-04-09
    • 2015-07-21
    • 1970-01-01
    相关资源
    最近更新 更多