I'm new to JavaFX and I want to create a view class that will call methods in a Controller when an event is triggered by a button push. My code is below:
package spacetrader.menu;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import spacetrader.Window;
public class MenuView implements Initializable {
public Window window;
public MenuCtrl menuCtrl;
@FXML
Button start;
@FXML
Pane background;
@FXML
Button exit;
public MenuView() {};
public MenuView(Window aWindow, MenuCtrl aMenuCtrl) {
window = aWindow;
menuCtrl = aMenuCtrl;
}
void renderMainMenu() {
try {
window.loadFXML(new FXMLLoader((getClass().getResource("MainMenu.fxml"))));
} catch (IOException ex) {
Logger.getLogger(MenuView.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void initialize(URL url, ResourceBundle rb) {
start.setOnAction((ActionEvent event) -> menuCtrl.newGame());
exit.setOnAction((ActionEvent event) -> menuCtrl.closeApplication());
}
}
This compiles, but when I run it and press the button I get a null pointer exception on the lambda expressions. The exception refers to "menuCtrl." How should I be setting up my program to make the button call menuCtrl.newGame()?
Here's what I've tried already:
Your setup is unusual, in that your controller class (which you've called MenuView
) is the class that calls (indirectly, via your Window
class) the FXMLLoader's load method. The FXMLLoader
parses the FXML, sees the fx:controller
attribute, and consequently instantiates it using the default (no-argument) constructor. (I am making an assumption here that you don't call setController
or setControllerFactory
on the FXMLLoader
in Window.loadFXML
.) Thus you have two controller instances: the one which created the loader (for whom the initialize() method is never called and the @FXML
-annotated fields are never injected), and one which was created by the FXMLLoader
(which called the no-argument constructor, so the window
and menuCtrl
fields are not initialized for that instance).
You should either refactor this, so that the FXMLLoader is created and passed to the Window class for loading elsewhere (i.e. without instantiating the controller), or you should explicitly set the controller on the FXMLLoader. You can achieve the latter in two steps:
fx:controller
attribute from MainMenu.fxmlrenderMainMenu
method:--
FXMLLoader loader = new FXMLLoader((getClass().getResource("MainMenu.fxml"))) ;
loader.setController(this);
window.loadFXML(loader);
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments