6

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

Community
  • 1
  • 1
user3505901
  • 408
  • 1
  • 6
  • 19
  • 1
    What's wrong with the other solution you suggested, i.e. `Tab newTab = new Tab();` `tabPane.getTabs().add(newTab);`? Just run that code in the event handler. You don't need to keep an additional list (or array) of the tabs, you can always get the current list with `tabPane.getTabs()`. – James_D Apr 06 '15 at 02:07
  • Because it creates a single tab and only will add one tab for each tab object I create. I need it to be dynamic so if my user has insane amounts of ram and wants to have 200 tabs open they can do so without me having to hardcode them in. – user3505901 Apr 06 '15 at 02:10
  • 1
    What's the UI for adding a large number of tabs? They enter the number they want to add in a text field and then press a button? I'm not sure I understand what you are trying to achieve. – James_D Apr 06 '15 at 02:11
  • So when the user clicks File -> New... they will get a new tab. Eventually I'll figure out a way to add a text area to it or something but at the moment I'm just trying to get this sorted out, how to create multiple tabs. Kinda like in NotePad++, you can have as many tabs open as you like, you know? – user3505901 Apr 06 '15 at 02:18
  • 1
    So just do it the way you said (as in my first comment). That will add a new tab every time the event handler is invoked. Why doesn't that work? – James_D Apr 06 '15 at 02:20
  • Another example is like any web browser, they all have address multiple tabs? That'swhat I want to implement but I can't figure out how to do it dynamically so I don't have to create 100 tab objects only to limit my users to 100 tabs. – user3505901 Apr 06 '15 at 02:22
  • 1
    Where is the limit coming from? Why are you creating the array at all? Just add a new tab in the event handler: that's all there is to it. – James_D Apr 06 '15 at 02:22
  • It doesn't work because it forces me to hardcode each tab object. So I have to make Tab tab1 = new Tab(), Tab tab2 = new Tab(), Tab tab3 = new Tab(), etc etc. – user3505901 Apr 06 '15 at 02:23

2 Answers2

7

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);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Yes! Perfect thank you! I'm not sure why what I did wasn't working at first since I'm pretty sure I tried something very similar to this. But I'm not sure why it didn't work. Anyway, thanks! I'd mark this as the solution but I don't think I have enough rep for that. – user3505901 Apr 06 '15 at 02:28
0

Use this instead. You have to override initialize() method:

@Override
public void initialize(URL location, ResourceBundle resources) {
    tabPane.getTabs().add(new Tab("Tab 1"));
} 

Not this:

public void initialize() {
    tabPane.getTabs().add(new Tab("Tab 1"));
}
Pochmurnik
  • 780
  • 6
  • 18
  • 35
Sadequer Rahman
  • 133
  • 5
  • 11