0

I'm new to the TabPanes, didn't really worked with them until now, and I need a TabPane with many Tabs but the same view(same look) for each Tab, what changes it is just the data in the tabs.

I have read JavaFX TabPane - One controller for each tab but this is not what I want, to assign a controller foreach tab. I want to do not duplicate my code, so I wold need to initialize the .fxml which contains my view only once and reuse it every time I swich between the tabs and load the appropriate data to it.

How can I achieve it?

My solution was:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.Tab?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="tabpane.Controller">
    <TabPane>
        <Tab>
            <fx:include source="CommonUI.fxml" fx:id="first"/>
        </Tab>
        <Tab>
            <fx:include source="CommonUI.fxml" fx:id="second"/>
        </Tab>
        <Tab>
            <fx:include source="CommonUI.fxml" fx:id="third"/>
        </Tab>
        <Tab>
            <fx:include source="CommonUI.fxml" fx:id="forth"/>
        </Tab>
        <Tab>
            <fx:include source="CommonUI.fxml" fx:id="fifth"/>
        </Tab>
    </TabPane>
</AnchorPane>


public class Controller implements Initializable {

    MyService setrvice = MyServiceProvider.getService(MyService.class);

    @FXML
    private CommonUIController firstController;
    @FXML
    private CommonUIController secondController;
    @FXML
    private CommonUIController thirdController;
    @FXML
    private CommonUIController forthController;
    @FXML
    private CommonUIController fifthController;



    @Override
    public void initialize(URL location, ResourceBundle resources) {
      // some code.
    }

    private void load() {
        firstController.load(service.firstData());
        secondController.load(service.secondData());
        thirdController.load(service.thirdData());
        forthController.load(service.forthData());
        fifthController.load(service.fifthData());
    }
}
Sunflame
  • 2,993
  • 4
  • 24
  • 48
  • 2
    [mcve] please .. you know the drill ;) – kleopatra Sep 18 '19 at 12:24
  • Well, true :) I'll edit it later – Sunflame Sep 18 '19 at 12:29
  • 1
    You have multiple tabs with the same view but different data, am I correct? In that case, you're right to not want separate controller _classes_ for each tab; instead you should have one controller class but multiple _instances_ of that class—one for each tab—and initialize each instance with different data. – Slaw Sep 18 '19 at 22:33
  • @Slaw Yeah, maybe this is the way to go. I was wondering if it would be better to have just one instance which handles everything and at tab switch I just replace the data. – Sunflame Sep 19 '19 at 07:38
  • While such an implementation may be possible, you should not share controller instances between different instances of the same view, same as you should not share controller classes between different FXML files. Semantically, a controller instance "belongs to" a single view instance. If you're worried about sharing state between controllers, that's where a well designed model comes into play. – Slaw Sep 19 '19 at 07:53
  • @Slaw Yes you are right, when I began to implement it, I thought, ah I have the same view, just the data differs, then lets implement as simple as possible with no duplicate code, so I thought it would be nice a single controller, but yeah later I realized better stick with more instance of the same controller as you say. – Sunflame Sep 19 '19 at 08:31

1 Answers1

1

Create instance of your controller and get view component. Then replace view and update data on tab change.

//pseudoCode
Node controllerView  = controller.getView();

TabPane tabPane = new TabPane();
tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldTab, tab) -> {
    if(oldTab != null) {
        oldTab.setContent(null);
    }
    if(tab != null) {
        tab.setContent(controllerView);
        //pseudoCode
        controller.updateData();
    }
});
MBec
  • 2,172
  • 1
  • 12
  • 15