javafx utilizando objetos de MainController u otros controladores en la clase de controlador adecuada

Tengo el siguiente código:

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() { @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() { @Override public void handle(ActionEvent event) { Platform.exit(); } }); } } 

Estoy tratando de usar WebEngine y ToggleButton Objects desde los controladores en MainController (les generé getters y setters en 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; } 

Pero aún así devuelve NullPointerException. Tuve el mismo problema, cuando intenté simplemente hacer referencias a los controladores en ConnectionErrorController. ¿Cómo hacer referencia a los objetos ToggleButton i WebEngine de los controladores en ConnectionErrorController correctamente? Saludos

Está creando una instancia de controlador “a mano” con

 MainController mc = new MainController(); 

@FXML FXML: los campos anotados son inicializados por FXMLLoader cuando crea el controlador para usted como parte del proceso de carga del archivo FXML. Dado que el controlador que ha creado no es la instancia del controlador creada por el FXMLLoader , sus campos @FXML -annotated no están inicializados (es decir, son nulos) y, por lo tanto, obtiene una excepción de puntero nulo.

Puede obtener una referencia al controlador creado por FXMLLoader llamando a getController() en la instancia de FXMLLoader después de llamar a load() .

Si desea que un controlador se comunique con otro, pase la referencia a un controlador al otro controlador, definiendo los métodos apropiados en el segundo controlador:

 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() { @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(); } }); // ... } } 

Suponiendo que está cargando el segundo archivo fxml en un método en MainController , puede hacer algo como:

 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... } // ... } 

Tenga en cuenta que hay formas mucho más elegantes de resolver este problema, como pasar el ConnectionErrorController una función de callback (en forma de una expresión lambda) para procesar la llamada a play(...) , lo que evita el estrecho acoplamiento entre ConnectionErrorController y el MainController . Sin embargo, como pareces ser nuevo en Java, este enfoque más simple podría ser más adecuado.

Consulte Pasar parámetros JavaFX FXML para obtener más información sobre cómo pasar valores a los controladores.