JavaFX:如何在没有 5 倍工作的情况下使用 SceneBuilder 在 TabPane 中创建 5 倍相同的标签?
JavaFX: How to create 5x identical Tabs within a TabPane with SceneBuilder, without 5x work?
如何使用 SceneBuilder 创建 5 倍相同的 TabPane,而不需要 5 倍的工作量?
- 一个 window 包含 5 个相同的 TabPane,具有非常多且复杂的 GUI 组件
- 我也想用SceneBuilder来设计window / tab
- 如何避免必须使用 SceneBuilder 设计 5 倍相同的 TabPane,尽管只有 fx:id 和 handle 方法
名称略有不同,例如:
TabPane0: tab0_textField_inputValue
TabPane1: tab1_textField_inputValue
TabPane2: tab2_textField_inputValue
等等
解决方案:
- 只需使用 SceneBuilder 设计一个 TabPane
- 但是你如何复制这个 "master"-TabPane 仍然是 4x,从而自动调整变量/方法名称?
- 复制应该是自动的,因为我经常需要它(在每个 GUI 开发步骤之后或
"master" 选项卡的更正/调整)
- 是否已经有一个工具可以相应地自动扩展 FXML 文件?
您通常创建一个仅包含单个 TabPane
的 fxml,然后使用 <fx:include>
:
多次使用此 fxml
tabpane.fxml
<TabPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="mapackage.TabPaneController">
...
</TabPane>
包含布局
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="mapackage.RootController">
<children>
<fx:include fx:id="tabPane1" source="@tabpane.fxml" />
<fx:include fx:id="tabPane2" source="@tabpane.fxml" />
...
</children>
</VBox>
public class RootController {
@FXML
private TabPaneController tabPane1Controller;
@FXML
private TabPaneController tabPane2Controller;
...
}
当然,您应该确保 TabPaneController
包含适当的方法来访问您需要从 RootController
...
访问的功能
解决方案:
谢谢你的帮助。我的解决方案如下所示:
- 我多次使用 TabView.fxml 输入
- 一旦用户点击一个选项卡,每个选项卡都必须分配一个唯一的 tabId
- 以下代码已完成且有效
Main.java
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(new AnchorPane());
FXMLLoader loader = new FXMLLoader(getClass().getResource("tabPaneRootView.fxml"));
scene.setRoot(loader.load());
TabPaneRootController controller = loader.getController();
controller.myInit(); //my init-Methode
primaryStage.setScene(scene);
primaryStage.setTitle("I'm Tab x");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TabPaneRootController.java
public class TabPaneRootController {
@FXML private TabPane tabPane;
//################################# Inject SubController ##################################
//Inject tab controller
@FXML private TabController xxx_tab1_xxxController; //TabPaneRootView.fxml_include_fx:id="xxx_tab_xxx" + "Controller"
@FXML private TabController xxx_tab2_xxxController;
//#########################################################################################
public void myInit() {
tabPane.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Tab> observable,
Tab oldValue, Tab newValue)->{
preparationInitTab(newValue);
});
}
public void preparationInitTab(Tab selectedTab) {
String currentTabId_string = selectedTab.getId();
String[] parts = currentTabId_string.split("_");
int currentTabId = Integer.parseInt(parts[1]);
switch(currentTabId) {
case 1:
xxx_tab1_xxxController.initTab(currentTabId);
break;
case 2:
xxx_tab2_xxxController.initTab(currentTabId);
break;
default:
System.out.println("Warning: Select an unassigned tab='" + currentTabId + "'");
}
}
}
TabController.java
public class TabController {
private int tabId = -9; //is the ID of the currently selected tab
@FXML private TextField tab_textField_currentTabName;
@FXML private TextField tab_textField01_costPosition1;
public void initTab(int currentTabId) {
System.out.println(">TabController::initTab() with currentTabId=" + currentTabId);
this.tabId = currentTabId;
tab_textField_currentTabName.setText(String.valueOf(tabId));
}
//----------------- FXML-Methoden --------------------------
@FXML
private void handleTabTextFieldCostPosition1() {
System.out.println("costPosition1[" + tabId + "]=" + tab_textField01_costPosition1.getText());
}
@FXML
private void handleExit() {
Platform.exit();
}
}
tabPaneRootView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.myapp.TabPaneRootController">
<children>
<TabPane fx:id="tabPane" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab fx:id="tabId_0" text="Tab0">
<content>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<Label layoutX="10.0" layoutY="30.0" text="general information ..." />
</children>
</AnchorPane>
</content>
</Tab>
<Tab fx:id="tabId_1" text="Tab1">
<content>
<fx:include source="tabView.fxml" fx:id="xxx_tab1_xxx" />
</content>
</Tab>
<Tab fx:id="tabId_2" text="Tab2">
<content>
<fx:include source="tabView.fxml" fx:id="xxx_tab2_xxx" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
tabView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.myapp.TabController">
<children>
<Label layoutX="10.0" layoutY="40.0" text="I'm Tab Index:"> </Label>
<TextField fx:id="tab_textField_currentTabName" editable="false" layoutX="107.0" layoutY="35.0" prefWidth="30.0" />
<Button alignment="CENTER" contentDisplay="CENTER" layoutX="185.0" mnemonicParsing="false" onAction="#handleExit" text="Exit" AnchorPane.bottomAnchor="10.0"> </Button>
<Label layoutX="10.0" layoutY="90.0" text="costPosition1 in € =" />
<TextField fx:id="tab_textField01_costPosition1" alignment="CENTER_RIGHT" layoutX="150.0" layoutY="85.0" onKeyReleased="#handleTabTextFieldCostPosition1" prefWidth="150.0" promptText="input an int value" />
</children>
</AnchorPane>
- Directory structure
- Example started
如何使用 SceneBuilder 创建 5 倍相同的 TabPane,而不需要 5 倍的工作量?
- 一个 window 包含 5 个相同的 TabPane,具有非常多且复杂的 GUI 组件
- 我也想用SceneBuilder来设计window / tab
- 如何避免必须使用 SceneBuilder 设计 5 倍相同的 TabPane,尽管只有 fx:id 和 handle 方法
名称略有不同,例如:
TabPane0: tab0_textField_inputValue
TabPane1: tab1_textField_inputValue
TabPane2: tab2_textField_inputValue
等等
解决方案:
- 只需使用 SceneBuilder 设计一个 TabPane
- 但是你如何复制这个 "master"-TabPane 仍然是 4x,从而自动调整变量/方法名称?
- 复制应该是自动的,因为我经常需要它(在每个 GUI 开发步骤之后或 "master" 选项卡的更正/调整)
- 是否已经有一个工具可以相应地自动扩展 FXML 文件?
您通常创建一个仅包含单个 TabPane
的 fxml,然后使用 <fx:include>
:
tabpane.fxml
<TabPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="mapackage.TabPaneController">
...
</TabPane>
包含布局
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="mapackage.RootController">
<children>
<fx:include fx:id="tabPane1" source="@tabpane.fxml" />
<fx:include fx:id="tabPane2" source="@tabpane.fxml" />
...
</children>
</VBox>
public class RootController {
@FXML
private TabPaneController tabPane1Controller;
@FXML
private TabPaneController tabPane2Controller;
...
}
当然,您应该确保 TabPaneController
包含适当的方法来访问您需要从 RootController
...
解决方案:
谢谢你的帮助。我的解决方案如下所示:
- 我多次使用 TabView.fxml 输入
- 一旦用户点击一个选项卡,每个选项卡都必须分配一个唯一的 tabId
- 以下代码已完成且有效
Main.java
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(new AnchorPane());
FXMLLoader loader = new FXMLLoader(getClass().getResource("tabPaneRootView.fxml"));
scene.setRoot(loader.load());
TabPaneRootController controller = loader.getController();
controller.myInit(); //my init-Methode
primaryStage.setScene(scene);
primaryStage.setTitle("I'm Tab x");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TabPaneRootController.java
public class TabPaneRootController {
@FXML private TabPane tabPane;
//################################# Inject SubController ##################################
//Inject tab controller
@FXML private TabController xxx_tab1_xxxController; //TabPaneRootView.fxml_include_fx:id="xxx_tab_xxx" + "Controller"
@FXML private TabController xxx_tab2_xxxController;
//#########################################################################################
public void myInit() {
tabPane.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Tab> observable,
Tab oldValue, Tab newValue)->{
preparationInitTab(newValue);
});
}
public void preparationInitTab(Tab selectedTab) {
String currentTabId_string = selectedTab.getId();
String[] parts = currentTabId_string.split("_");
int currentTabId = Integer.parseInt(parts[1]);
switch(currentTabId) {
case 1:
xxx_tab1_xxxController.initTab(currentTabId);
break;
case 2:
xxx_tab2_xxxController.initTab(currentTabId);
break;
default:
System.out.println("Warning: Select an unassigned tab='" + currentTabId + "'");
}
}
}
TabController.java
public class TabController {
private int tabId = -9; //is the ID of the currently selected tab
@FXML private TextField tab_textField_currentTabName;
@FXML private TextField tab_textField01_costPosition1;
public void initTab(int currentTabId) {
System.out.println(">TabController::initTab() with currentTabId=" + currentTabId);
this.tabId = currentTabId;
tab_textField_currentTabName.setText(String.valueOf(tabId));
}
//----------------- FXML-Methoden --------------------------
@FXML
private void handleTabTextFieldCostPosition1() {
System.out.println("costPosition1[" + tabId + "]=" + tab_textField01_costPosition1.getText());
}
@FXML
private void handleExit() {
Platform.exit();
}
}
tabPaneRootView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.myapp.TabPaneRootController">
<children>
<TabPane fx:id="tabPane" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab fx:id="tabId_0" text="Tab0">
<content>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<Label layoutX="10.0" layoutY="30.0" text="general information ..." />
</children>
</AnchorPane>
</content>
</Tab>
<Tab fx:id="tabId_1" text="Tab1">
<content>
<fx:include source="tabView.fxml" fx:id="xxx_tab1_xxx" />
</content>
</Tab>
<Tab fx:id="tabId_2" text="Tab2">
<content>
<fx:include source="tabView.fxml" fx:id="xxx_tab2_xxx" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
tabView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.myapp.TabController">
<children>
<Label layoutX="10.0" layoutY="40.0" text="I'm Tab Index:"> </Label>
<TextField fx:id="tab_textField_currentTabName" editable="false" layoutX="107.0" layoutY="35.0" prefWidth="30.0" />
<Button alignment="CENTER" contentDisplay="CENTER" layoutX="185.0" mnemonicParsing="false" onAction="#handleExit" text="Exit" AnchorPane.bottomAnchor="10.0"> </Button>
<Label layoutX="10.0" layoutY="90.0" text="costPosition1 in € =" />
<TextField fx:id="tab_textField01_costPosition1" alignment="CENTER_RIGHT" layoutX="150.0" layoutY="85.0" onKeyReleased="#handleTabTextFieldCostPosition1" prefWidth="150.0" promptText="input an int value" />
</children>
</AnchorPane>
- Directory structure
- Example started