0

I have following code:

package pl.javastart.youtufy.controller;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;

public class ConnectionErrorController implements Initializable {

    @FXML
    private Label infoLabel;

    @FXML
    private Button tryButton;

    @FXML
    private Button exitButton;


    @Override
    public void initialize(URL location, ResourceBundle resources) {

        MainController mc = new MainController();

        infoLabel.setText("Connection lost, please try again");
        tryButton.setText("try again");
        exitButton.setText("exit");

        tryButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

                WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
                ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
                Node source = (Node) event.getSource();
                Stage stage = (Stage) source.getScene().getWindow();
                if (mc.testInet()) {
                    stage.close();
                    mc.play(webEngine, playButton);
                } else {
                    stage.close();
                    MainController.exist = false;
                }
            }
        });

        exitButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Platform.exit();
            }
        });
    }

}

I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):

public class MainController implements Initializable {

@FXML
private ContentPaneController contentPaneController;

@FXML
private ControlPaneController controlPaneController;

@FXML
private MenuPaneController menuPaneController;

@FXML
private SearchPaneController searchPaneController;

private Youtube youtubeInstance;

public static boolean exist = false;

public ControlPaneController getControlPaneController() {
    return controlPaneController;
}

public void setControlPaneController(ControlPaneController controlPaneController) {
    this.controlPaneController = controlPaneController;
}

public ContentPaneController getContentPaneController() {
    return contentPaneController;
}

public void setContentPaneController(ContentPaneController contentPaneController) {
    this.contentPaneController = contentPaneController;
}

But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly? Regards

James_D
  • 201,275
  • 16
  • 291
  • 322
MikolajMGT
  • 113
  • 2
  • 10

1 Answers1

1

You are creating a controller instance "by hand" with

MainController mc = new MainController();

@FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its @FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.

You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().

If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:

public class ConnectionErrorController implements Initializable {

    private MainController mainController ;

    public void setMainController(MainController mainController) {
        this.mainController = mainController ;
    }

    // ...

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        infoLabel.setText("Connection lost, please try again");
        tryButton.setText("try again");
        exitButton.setText("exit");

        tryButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

                WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
                ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
                if (mainController.testInet()) {
                    mainController.play(webEngine, playButton);
                } else {
                    // obviously you can now do something better than the "public static field hack" here:
                    MainController.exist = false;
                }
                tryButton.getScene().getWindow().hide();
            }
        });

        // ...
    }
}    

Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:

public class MainController {

    // ...

    public void showConnectionErrorWindow(String fileName) {

        FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
        Parent root = loader.load();
        ConnectionErrorController connectionErrorController = loader.getController();
        connectionErrorController.setMainController(this);

        Scene scene = new Scene(root);
        Stage stage = new Stage();
        // etc...
    }

    // ...
}

Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.

See Passing Parameters JavaFX FXML for more information on passing values to controllers.

Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322