-1

I want to create a project with two forms, but now there's a problem when I try to call a method in the second controller from the first controller. I've created a minimal reproducible example for simplicity. The two controllers are as follows:

package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
import javafx.stage.Stage;

public class Controller {
    @FXML Button btnNew;

    public void switchHandler (ActionEvent evt) {
        try {
            launch(Main.getStage(), "sample2.fxml", "");
            Controller2 cont = new Controller2();
            cont.text();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void launch(Stage primaryStage, String form, String title) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource(form));
        primaryStage.setTitle(title);
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();
    }
}

And the second controller:

package sample;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class Controller2 {
    @FXML
    TextField txt;

    public void text() {
        txt.setText("Hello World"); //this line goes wrong
    }
}

The forms are as follows:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>


<AnchorPane 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">
   <children>
      <Button fx:id="btnNew" onAction="#switchHandler" layoutX="213.0" layoutY="145.0" mnemonicParsing="false" text="Button" />
   </children>
</AnchorPane>

And the second form:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller2">
   <children>
      <TextField fx:id="txt" layoutX="151.0" layoutY="156.0" />
   </children>
</AnchorPane>

The line txt.setText("Hello World"); produces a NullPointerException. Can someone tell me why and how to fix this problem?

Richard
  • 1
  • 2
  • you must load a controller (vs instantiating it) to have its fields injected – kleopatra Oct 20 '20 at 05:31
  • @kleopatra Can you specify how to do that? – Richard Oct 20 '20 at 06:39
  • 1
    When you have `fx:controller` in the FXML file then that class is instantiated by the `FXMLLoader` for you (via its controller factory, which uses reflection by default) when you call `load()`. It's _that_ instance that's "managed" by the `FXMLLoader` and thus the one who has its fields injected. You can get that controller instance via `FXMLLoader#getController()`, but that means you'll have to create an instance of `FXMLLoader` instead of using the static `load(URL)` method. Remember, you must call `load()` _before_ using `getController()` else you'll get null. – Slaw Oct 20 '20 at 06:45

1 Answers1

1

A small sample for you. Just replace with your classes. You should do something like that:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/sample2.fxml"));
Parent root = fxmlLoader.load();
MyController controller = fxmlLoader.getController();

... //show scene etc.

controller.text();
Raw
  • 461
  • 7
  • 15