用单独的场景替换 TabPane (JAVAFX)

Replace TabPane with separate scenes (JAVAFX)

目前我的 TabPane 有 3 个活动标签。我必须在它们之间手动切换,这并不理想。我想做的是一起替换 TabPane 并在舞台内有一个场景,然后按下按钮切换到下一个场景(从 Tab1,到 Tab2,再到 Tab3)。

维护设置标签文本功能很重要。

Tab1

Tab2

Main.java

package application;

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

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("../view/Main.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }


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

MainController.java

package controller;

import javafx.fxml.FXML;
import controller.tab.Tab1Controller;
import controller.tab.Tab2Controller;
import controller.tab.Tab3Controller;

public class MainController {

    @FXML Tab1Controller tab1Controller;
    @FXML Tab2Controller tab2Controller;
    @FXML Tab3Controller tab3Controller;

    public void initialize() {
        tab1Controller.init(this);
        tab2Controller.init(this);
        tab3Controller.init(this);
    }

    public void setTab2LabelText(String text) {

        tab3Controller.lbl3.setText(text);
        tab2Controller.lbl2.setText(text);
    }
}

Tab1Controller.java

package controller.tab;

import controller.MainController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

import java.io.IOException;

public class Tab1Controller {

    private MainController main;

    @FXML public Label lbl1;
    @FXML private Button btn1Send;

    @FXML private void btn1SendClicked(ActionEvent event) throws IOException {
        main.setTab2LabelText("abc");
    }

    public void init(MainController mainController) {
        main = mainController;
    }
}

Tab2Controller.java

package controller.tab;

import controller.MainController;
import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class Tab2Controller {

    private MainController main;

    @FXML public Label lbl2;

    public void init(MainController mainController) {
        main = mainController;
    }
}

Tab3Controller.java

package controller.tab;

import controller.MainController;
import javafx.fxml.FXML;
import javafx.scene.control.Label;


public class Tab3Controller {

    private MainController main;

    @FXML public Label lbl3;

    public void init(MainController mainController) {
        main = mainController;
    }

}

Main.fxml

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

<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="432.0" prefWidth="443.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainController">
    <children>
        <TabPane prefHeight="299.0" prefWidth="309.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
            <tabs>
                <Tab closable="false" text="Tab 1">
                    <content>
                        <fx:include fx:id="tab1" source="tab/Tab1.fxml" />
                    </content></Tab>
                <Tab closable="false" text="Tab 2">
                    <content>
                        <fx:include fx:id="tab2" source="tab/Tab2.fxml" />
                    </content></Tab>
                <Tab closable="false" text="Tab 3">
                    <content>
                        <fx:include fx:id="tab3" source="tab/Tab3.fxml" />
                    </content></Tab>
            </tabs>
        </TabPane>
    </children>
</AnchorPane>

Tab2.fxml

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

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

<AnchorPane prefHeight="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab1Controller">
    <children>
        <Button fx:id="btn1Send" layoutX="42.0" layoutY="74.0" mnemonicParsing="false" onAction="#btn1SendClicked" prefHeight="58.0" prefWidth="142.0" text="Send to Tab2 &amp; Tab3" />
    </children>
</AnchorPane>

Tab2.fxml

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab2Controller">
    <children>
        <Label fx:id="lbl2" alignment="CENTER" layoutX="37.0" layoutY="46.0" prefHeight="17.0" prefWidth="152.0" text="Default Tab2 text" />
    </children>
</AnchorPane>

Tab3.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="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab3Controller">
    <children>
        <Label fx:id="lbl3" alignment="CENTER" layoutX="37.0" layoutY="46.0" prefHeight="17.0" prefWidth="152.0" text="Default Tab3 text" />
    </children>
</AnchorPane>

这是一个例子

fxml

创建 3 个面板,有自己的按钮和标签

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="380.0" prefWidth="387.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ask.FXMLDocumentController">
   <children>
      <Pane fx:id="p3" prefHeight="380.0" prefWidth="387.0" visible="false">
         <children>
            <Label layoutX="184.0" layoutY="181.0" text="p3" />
            <Button fx:id="p3previous" layoutX="152.0" layoutY="225.0" mnemonicParsing="false" text="previous" />
         </children>
      </Pane>
      <Pane fx:id="p2" prefHeight="380.0" prefWidth="387.0" visible="false">
         <children>
            <Label layoutX="184.0" layoutY="181.0" text="p2" />
            <Button fx:id="p2previous" layoutX="78.0" layoutY="255.0" mnemonicParsing="false" text="previous" />
            <Button fx:id="p2next" layoutX="239.0" layoutY="255.0" mnemonicParsing="false" text="next" />
         </children>
      </Pane>
      <Pane fx:id="p1" prefHeight="380.0" prefWidth="387.0">
         <children>
            <Button fx:id="p1next" layoutX="167.0" layoutY="210.0" mnemonicParsing="false" text="next" />
            <Label layoutX="184.0" layoutY="181.0" text="p1" />
         </children>
      </Pane>
   </children>
</AnchorPane>

控制器

添加按钮动作事件,使用setVisible(boolean)控制显示哪个窗格。

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;

public class FXMLDocumentController implements Initializable {

    @FXML Pane p1;
    @FXML Pane p2;
    @FXML Pane p3;
    @FXML Button p1next;
    @FXML Button p2next;
    @FXML Button p2previous;
    @FXML Button p3previous;

    public void initialize(URL url, ResourceBundle rb) 
    {
        p1next.setOnAction(e->{ p1.setVisible(false); p2.setVisible(true); });
        p2next.setOnAction(e->{ p2.setVisible(false); p3.setVisible(true); });
        p2previous.setOnAction(e->{ p2.setVisible(false); p1.setVisible(true); });
        p3previous.setOnAction(e->{ p3.setVisible(false); p2.setVisible(true); });
    }  
}

您不需要将在 fxml 文件中创建的所有内容都添加到场景中。 <fx:define> 标签可用于创建不属于对象场景的 Node(目前)。使用合适的 Parent 可以让您正确显示内容。

示例:

<StackPane fx:id="container" prefHeight="432.0" prefWidth="443.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainController">
    <children>
        <fx:include fx:id="tab1" source="tab/Tab1.fxml" />
        <fx:define>
            <fx:include fx:id="tab2" source="tab/Tab2.fxml" />
            <fx:include fx:id="tab3" source="tab/Tab3.fxml" />
        </fx:define>
    </children>
</StackPane>
public class MainController {

    @FXML private Tab1Controller tab1Controller;
    @FXML private Tab2Controller tab2Controller;
    @FXML private Tab3Controller tab3Controller;

    @FXML private Node tab1;
    @FXML private Node tab2;
    @FXML private Node tab3;

    @FXML private StackPane container;

    public void initialize() {
        tab1Controller.init(this);
        tab2Controller.init(this);
        tab3Controller.init(this);
    }

    public void setTab2LabelText(String text) {
        tab3Controller.lbl3.setText(text);
        tab2Controller.lbl2.setText(text);
    }

    public void toTab2() {
        container.getChildren().setAll(tab2);
    }
}