user3505901 user3505901 - 1 month ago 23
Java Question

How to create tabs dynamically in JavaFX using FXML?

How do you create a new tab using JavaFX/FXML? I've created a tabpane in my FXML but I want to click a button that causes a new tab to come up.

Here is my FXML:


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


<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="New..." onAction="#btnNew"/>
<MenuItem mnemonicParsing="false" text="Save..." />
<MenuItem mnemonicParsing="false" text="Save As..." />
<MenuItem mnemonicParsing="false" text="Open..." />
<MenuItem mnemonicParsing="false" text="Close" />

</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About Blank" onAction="#btnAbout"/>
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER" fx:id="tabPane">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<AnchorPane>
<children>
<TextFlow maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>





Here is my code that I'm trying right now in my controller:

package sample;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import java.net.URL;
import java.util.ResourceBundle;


public class Controller implements Initializable {
@FXML
private Button btnAbout;
@FXML
private Button btnNew;
@FXML
private TabPane tabPane;

//tab array
int intTabs = 0;
Tab[] openTabs;

@FXML
private void btnNew(ActionEvent event){
try{
intTabs++;
openTabs = new Tab[intTabs];
//System.out.println(openTabs.length);
tabAdder(intTabs, openTabs);
}catch(Exception e){
e.printStackTrace();
}

}

private TabPane tabAdder(int tabNum, Tab[] tabs){
//System.out.println(tabNum);
tabPane.getTabs().add(tabs[tabNum]);
return tabPane;
}

@FXML
private void btnAbout(ActionEvent event){
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Blank: Information");
alert.setHeaderText(null);
alert.setContentText("This is Blank, a simple and soon to be elegant cross platform text editor.");
alert.showAndWait();
}


public void initialize(URL url, ResourceBundle rb){
//tabPane.getTabs().add

}


}

I'm not really sure what the problem is I've been going through a bunch of resources and I know how to add a regular tab.

I know that if I make a tab like this:

Tab fapTab = new Tab();


I can add it like this:

tabPane.getTabs().add(fapTab);


But I want to create them dynamically because I don't know how many tabs my user's would want. So my approach was to create an array of tabs that gets bigger whenever a user clicks "new" and then have a function that adds that new tab to the gui. It's not working though and I've tried several different approaches, adapting people's code to my own.

So my question is does anyone know what I'm doing wrong?

Here are some of those sources:
javafx open a new fxml file in new tab dynamically
http://javafx-albert-af77.blogspot.com/2012/06/tabs-fxml.html
https://www.youtube.com/watch?v=NhoiSMk3f5U

Answer

You have already given the answer: just create a new tab and add it to the tab pane:

Tab tab = new Tab();
tabPane.getTabs().add(tab);

Complete example:

AddTabsExample.fxml:

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

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="AddTabsController">
    <center>
        <TabPane fx:id="tabPane" />
    </center>
    <bottom>
        <HBox alignment="center">
            <Button text="Add tab" onAction="#addTab" />
            <Button text="List tabs" onAction="#listTabs" />
        </HBox>
    </bottom>
</BorderPane>

AddTabsController.java:

import javafx.fxml.FXML;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;

public class AddTabsController  {

    @FXML
    private TabPane tabPane ;

    public void initialize() {
        tabPane.getTabs().add(new Tab("Tab 1"));
    }

    @FXML
    private void addTab() {
        int numTabs = tabPane.getTabs().size();
        Tab tab = new Tab("Tab "+(numTabs+1));
        tabPane.getTabs().add(tab);
    }

    @FXML
    private void listTabs() {
        tabPane.getTabs().forEach(tab -> System.out.println(tab.getText()));
        System.out.println();
    }
}

Application (AddTabsExample.java):

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

public class AddTabsExample extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane root = FXMLLoader.load(getClass().getResource("AddTabsExample.fxml"));
        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();
    }

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