3

Currently i have TabPane with 3 active tabs. I have to manually switch between them, which isn't ideal. What i would like to do is replace the TabPane all together and have one scene inside the stage, which would then switch to next scene (From Tab1, to Tab2, to Tab3) upon press of a button.

It is important to maintain the set label text functionality.

Tab1

Tab1

Tab2

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>
Cœur
  • 37,241
  • 25
  • 195
  • 267
Elion
  • 33
  • 5

2 Answers2

1

Here is a example

fxml

create 3 panes, with its own button and label

<?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>

controller

add button action event, use setVisible(boolean) to control which pane should show.

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); });
    }  
}
TomN
  • 574
  • 3
  • 18
  • Hey, thank you for your input. Would you happen to also know how i could add `@FXML` file for each seperate pane or is there a better way to edit `p1`, `p2` and `p3`? – Elion Dec 05 '16 at 10:29
  • This may help. http://stackoverflow.com/questions/22161586/javafx-embed-scene-in-scene – SedJ601 Dec 05 '16 at 14:48
  • @Elion plz check fabian's answer – TomN Dec 06 '16 at 04:06
  • @TomN Yes, thanks to both of you. I wish i could give out more than one green tick! Case closed. ^.^ – Elion Dec 06 '16 at 16:08
1

You do not need to add all the content you create in a fxml file to the scene. the <fx:define> tag can be used to create Node that are not part of the object scene (yet). Use a suitable Parent that allows you to proper display the content.

Example:

<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);
    }
}
fabian
  • 80,457
  • 12
  • 86
  • 114