0

How can I start a method every time a tab is called? I have a Main.fxml with a tabpane and two tabs, I've included a separate fxml for each tab (tab1.fxml, tab2.fxml).

Main.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="434.0" prefWidth="428.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainController">
   <children>
  <TabPane prefHeight="434.0" prefWidth="428.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
    <tabs>
      <Tab fx:id="tab1" text="Tab 1">
           <content>
              <fx:include source="tab1.fxml" />
           </content>
      </Tab>
      <Tab fx:id="tab2" onSelectionChanged="#addView" text="Tab 2">
           <content>
              <fx:include source="tab2.fxml" />
           </content>
      </Tab>
    </tabs>
  </TabPane>
 </children>
</AnchorPane>      

MainController.java

public class MainController implements Initializable{

    @FXML private Tab tab1;
    @FXML private Tab tab2;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {

    }


    @FXML public void addView(){

    }
}

Each FXML has a Label which should show how often the tab(content) was called. So if I click on tab ("tab2") the counter label should show "1" and increment by +1 every time I call this tab again. This should happen by using a method within the tab controllers.

tab1.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="249.0" prefWidth="257.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab1Controller">
   <children>
     <Label fx:id="lbl_1" layoutX="92.0" layoutY="53.0" text="not clicked" />
   </children>
</AnchorPane>

tab1Controller.java

public class tab1Controller implements Initializable{


     @FXML public  Label lbl_1;

     private static int counter=0;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {


    }

    public void addViewCounter(){
        lbl_1.setText(""+counter);
        counter++;
    }
}

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="249.0" prefWidth="257.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab2Controller">
   <children>
     <Label fx:id="lbl_2" layoutX="92.0" layoutY="53.0" text="not clicked" />
   </children>
</AnchorPane>

tab2Controller.java

public class tab1Controller implements Initializable{


     @FXML public  Label lbl_2;

     private static int counter=0;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {


    }

    public void addViewCounter(){
        lbl_2.setText(""+counter);
        counter++;
    }
}

I've already tried to solve this problem by using static methods and labels but i get NullPointerExceptions, seems like this doesn't work anymore with java 8. Also I've tried to get the controller by using a FXMLloader ... this way I also get a NullPointerExceptions.

Isn't there an onCall method for the included fmxl or the anchorpane? Or maybe something that makes the controller initialize again.

Any other solutions or ideas?

Ahmed Salman Tahir
  • 1,783
  • 1
  • 17
  • 26
VRage
  • 1,458
  • 1
  • 15
  • 27

1 Answers1

2

Firstly, your counters should not be static. They belong to the controller instances, not the controller class.

You need three things:

  1. A reference to the tabPane in the main controller
  2. A reference to each of the tab controllers in the main controller.
  3. A listener on the tabPane's selected tab, so that you can call a method when the selected tab changes

For the first, just do:

<TabPane fx:id="tabPane" prefHeight="434.0" ... >

in Main.fxml, and

@FXML private TabPane tabPane ;

in MainController.java.

For the second, you can use the "Nested Controller" technique.

You need to add an fx:id attribute to each of the fx:includes, and then just add references for the controllers in MainController.java. The rule is that if your fx:include has fx:id="x", then the controller from the corresponding FXML file can be injected into a variable with name xController. Here I have changed the class names for the controllers to Tab1Controller and Tab2Controller to follow the standard conventions (and avoid confusion).

In Main.fxml, change the fx:includes to include an fx:id:

<fx:include fx:id="tab1Content" source="tab1.fxml" />

<fx:include fx:id="tab2Content" source="tab2.fxml" />

In MainController.java:

@FXML private Tab1Controller tab1ContentController ;
@FXML private Tab2Controller tab2ContentController ;

Now in MainController's initialize() method just set up the listener:

public void initialize() {
    tabPane.getSelectionModel().selectedItemProperty()
        .addListener((obs, oldTab, newTab) -> {
            if (newTab == tab1) {
                tab1ContentController.addViewCounter();
            } else if (newTab == tab2) {
                tab2ContentController.addViewCounter();
            }
        });
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Wow, thank you very much. I've already tried this approach, but i missed to add the "Controller" after the fx:id-name, so i did get error messages all the time. – VRage Nov 14 '14 at 21:30