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?
Firstly, your counter
s should not be static
. They belong to the controller instances, not the controller class.
You need three things:
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:include
s, 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:include
s 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();
}
});
}