Reputation: 105
I have a reduced example of my problem where the code references from fx:id
are not null when the initialize
is called but then go to null right after the function call. What is the correct way to get such references? This is sample.fxml
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sample.Main">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<Text fx:id="textRef" strokeType="OUTSIDE" strokeWidth="0.0" text="Hello world" />
</children>
</GridPane>
And this is the Main.java
which is declared as its controller.
public class Main extends Application implements Initializable{
@FXML
public Text textRef;
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
this.someNewFunction();
}
private void someNewFunction() {
this.textRef.setText("Changed in somNewFunction");
}
public static void main(String[] args) {
launch(args);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
this.textRef.setText("Changed at initialize");
}
}
The text ref is valid inside the initialize
call but throws a nullpointerexception when inside the someNewFunction
.
Upvotes: 2
Views: 1669
Reputation: 82461
The Main
instance that is launched is a different object than the Main
instance created by the FXMLLoader
to be used as controller.
IMHO it would be better to get the controller from the FXMLLoader
after loading the fxml and also use a class different to the Application
as controller:
public class MainController implements Initializable {
...
}
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sample.MainController">
...
</GridPane>
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
MainController controller = loader.getController();
controller.someNewFunction();
}
However you could also specify the controller that should be used with the fxml:
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
...
</GridPane>
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
loader.setController(this);
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
this.someNewFunction();
}
Upvotes: 4
Reputation: 643
You are executing the someNewFunction outside the javafx loop. I mean, after the show method ends, the main thread takes control and the javafx components no longer exists (they are destroyed as is supposed that they are no longer needed). You have to bind the someNewFunction to some event attached to some FXML element reference (i.e. a Button via the setOnAction on SceneBuilder, or via code), place the method call inside the initialize method, or simply move the call before the primaryStage.show() line.
Hopes this helps
Upvotes: 0