Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace TabPane with separate scenes (JAVAFX)

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>
like image 442
Elion Avatar asked Mar 20 '26 11:03

Elion


2 Answers

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); });
    }  
}
like image 96
TomN Avatar answered Mar 24 '26 23:03

TomN


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);
    }
}
like image 27
fabian Avatar answered Mar 25 '26 01:03

fabian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!