Cannot seem to instantiate a non-null FXMLLoader - java

I have read a few of the related posts on this topic but have been unable to use them to solve my issue. I believe my failure is one of comprehension and not that I am facing a unique issue. But, I am at a total impasse.
I'm building a CRUD application using JavaFX. One of my application's buttons, "Import Data," is throwing NullPointerExceptions:
// *a button that opens a new window with a textField where the user can paste text data*
#FXML
private void importDataButton(ActionEvent event) {
// *load the fxml file*
URL viewLocation = getClass().getResource("/importView.fxml");
// *get the file's controller*
FXMLLoader loader = new FXMLLoader();
ImportController importController = loader.getController();
importController.setMainController(this);
loader.setLocation(viewLocation);
try {
loader.load();
} catch (IOException exception) {
System.out.println("IO Exception thrown.");
return;
}
....
}
I'm not very good with IntelliJ's debugger yet, but I've used it to determine that the FXMLLoader object is null. So when
importController.setMainController(this);
executes, a NullPointerException is thrown because the object this refers to is null. I...think. So then
ImportController importController = loader.getController();
cannot retrieve the controller from the FXMLLoader object (loader).
For reference, setMainController() is in another class called ImportController, and that method's code is as follows:
public void setMainController(MainController mainController) {
this.mainController = mainController;
}
Things I've tried:
I read this post and this post, both of them recommend that I must run loader.load() [given FXMLLoader loader = new FXMLLoader()] in order to retrieve data from the object. However, I've tried this, and I just get errors upon errors: InvocationTargetExceptions and IllegalStateExceptions. I have also tried instantiating an FXMLLoader object that is non-null, using
FXMLLoader load = new FXMLLoader(getClass.getResource("sample.fxml"));
But it seems to have no effect on the content of the object (and yes, I am replacing "sample.fxml" with my filename.)
I hate to make a similar post, but I have no idea what to do.

The problem is that you are calling loader.getController() before loader.load(). That's why your importController is null when calling importController.setMainController(this).
Call loader.load() first:
URL viewLocation = getClass().getResource("/importView.fxml");
FXMLLoader loader = new FXMLLoader(viewLocation);
try {
loader.load();
ImportController importController = loader.getController();
importController.setMainController(this);
} catch (IOException exception) {
exception.printStackTrace();
}
But be aware that the initialize() method in your ImportController is called before setMainController().

Related

Cannot invoke the presenter because it is null, MVP architecture with JavaFX [duplicate]

I am having the following problem with a program that I am currently writing, and I have searched on the internet, but I couldn't really find anything to help me understand the following problem
So inside another class I have written a method that executes this whenever the search button is clicked and the method looks like this:
public void searchButton(){
try {
new SearchController().display();
} catch (IOException e) {
e.printStackTrace();
}
}
And then the SearchController class looks something like this (I simplified it here):
public class SearchController {
#FXML
private Button cancelButton;
#FXML
private Label what;
private static Stage stage;
private static BorderPane borderPane;
#FXML
public void initialize(){
what.setText("Testing"); // this woks
cancelButton.setOnAction(e -> stage.close());
}
public void display() throws IOException {
stage = new Stage();
stage.setResizable(false);
stage.setTitle("Product search");
stage.initModality(Modality.APPLICATION_MODAL);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(SearchController.class.getResource("Search.fxml"));
borderPane = loader.load();
Scene scene = new Scene(borderPane);
stage.setScene(scene);
//what.setText("Testing") and this doesn't work
stage.showAndWait();
}
}
Can someone please tell me why it is possible to write text on the initialize method (that method gets called after the borderPane = loader.load(); line...so why doesn't it work if I try to write on the label after that line?)
Thank you in advance
The FXMLLoader creates an instance of the class specified in the fx:controller attribute of the FXML root element. It then injects the elements defined in the FXML file into the controller instance it created when the fx:id attributes match the field names. Then it calls the initialize() method on that instance.
You create an instance of the controller "by hand" with new SearchController(). This is not the same object that is created by the FXMLLoader. So now when you have loaded the fxml file you have two different instances of SearchController. So if you call what.setText(...) from the display() method, you are not calling it on the controller instance created by the FXMLLoader. Consequently, what has not been initialized in the instance on which you are calling what.setText(...), and you get a null pointer exception.
Since initialize() is invoked by the FXMLLoader on the instance it created, when you call what.setText(...) from the initialize() method, you are calling it on the instance created by the FXMLLoader, and so the FXML-injected fields for that instance have been initialized.

javafx load generic controller from fxml

I want to achieve generic code for loading fxml and set data for that fxml. Following is my function to load child fxml. Now i want to figure out how i can get controller name from getLoader and do not need to hard-code OwnerViewController. So i can set data for each fxml pass to the function argument. My controller have OwnerViewController setData method and its working fine. I just want to make my controller name to dyanamic.
public void loadAnchorPaneWithData(AnchorPane ap, String a, Object data) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/herudi/view/"+a));
AnchorPane p = loader.load();
OwnerViewController controller = loader.getController();
controller.setData(data);
ap.getChildren().setAll(p);
} catch (IOException e) {
}
}

How to update controller with FXMLLoader?

I am able to grab the FXMLLoader controller for my controller and I am now wanting to update a method inside it. How can I do this?
#Override
public void handle(MouseEvent event)
{
FXMLLoader loader = new FXMLLoader(
getClass().getResource(UIViewConstants.HIERARCHY_TAB_FULLNAME));
HierarchyTabController controller = new HierarchyTabController(dataModel);
loader.setController(controller);
System.out.println(loader);
loader.updateTable(dataModel) //How can I make this work?
}
In my HierarchyTabController I have a method called updateTable so how can I call that from the instance I am getting now from loader?
If it helps, it prints out the object java.fx.fxml.FXMLLoader#16F451AA
This is how I would implement it:
Parent root;
try {
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getClassLoader().getResource
(UIViewConstants.HIERARCHY_TAB_FULLNAME)); // getClassLoader() to avoid problems to find the resources when generating the jar file
root = (Parent)fxmlLoader.load();
HierarchyTabController controller =
fxmlLoader.<HierarchyTabController>getController();
controller.updateTable(dataModel);
} catch (IOException e) {
logger.debug(e);
}

FXML Resource isn't loading

I am developing a simple JavaFX application and I cannot load one of the resources (login.fxml), even though I can load the other that is in the same folder (main.fxml).
My folder organization is in the screenshot below. The error is in the line 50 (highlighted)
The loadVista method source code:
public static void loadVista(String fxml) {
try {
mainController.setVista(
FXMLLoader.load(
Navigator.class.getResource(
fxml
)
)
);
} catch (IOException e) {
e.printStackTrace();
}
}
Can somebody help me?
Thanks in advance,
Gabriel
EDIT: a part of stacktrace:
Caused by: java.lang.NullPointerException
at sisgem.view.Navigator.loadVista(Navigator.java:45)
at sisgem.SisGEMApplication.loadMainPane(SisGEMApplication.java:50)
at sisgem.SisGEMApplication.start(SisGEMApplication.java:25)
mainController is null, so you get a NullPointerException when you call mainController.setVista(...). This is because you use the static method FXMLLoader.load(URL) to load the FXML, and never invoke load on the FXMLLoader instance loader. Since that instance never executes its load() method, its controller is never initialized, and loader.getController() returns null.
So your loadMainPane() method should look like
private Pane loadMainPane() throws IOException {
FXMLLoader loader = new FXMLLoader(Navigator.class.getResource(Navigator.PANE));
Pane mainPane = loader.load();
MainController mainController = loader.getController();
Navigator.setMainController(mainController);
Navigator.loadVista("login.fxml");
return mainPane ;
}

How to Pass Values to Window in JavaFX

I am trying to pass a stored preference value to a text box in a settings window that can be opened from a user login window. I am planning to do this by setting the value in the controller prior to open. As you can see, I am also trying to make the settings window a child of the login window. However, I am getting javafx.scene.layout.AnchorPane cannot be cast to javafx.fxml.FXMLLoader for reasons that I don't understand and am completely at a loss as to what to do.
My code for opening the settings window on the press of a button is as follows:
#FXML
void OpenSettingsWindow(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader = FXMLLoader.load(SettingsWindowController.class
.getResource("Settings.fxml"));
AnchorPane page = (AnchorPane) FXMLLoader.load(SettingsWindowController.class
.getResource("Settings.fxml"));
Scene scene = new Scene(page);
root = new Stage();
root.initModality(Modality.WINDOW_MODAL);
root.initOwner(Main.primaryStage);
root.setScene(scene);
SettingsWindowController controller = fxmlLoader.getController();
String databaseAddressValue = "databaseAddressValue";
controller.setDatabaseAddressValue(Preferences
.systemRoot()
.node("preferences.SystemPreferences")
.get(SystemPreferences.databaseAddress, databaseAddressValue));
root.show();
} catch (Exception e) {
e.printStackTrace();
}
Any advice as to how to fix this is much appreciated.
You are assigning the return value of FXMLLoader.load() to a FXMLLoader reference.
FXMLLoader.load() returns the highest object in you FXML file and that is for sure not a FXMLLoader object.
If you want to use a controller class for event handling and proper intialization you have to set it first and load the FXML in an other way (I assume that the SettingsWindowController is your controller class and has a default constructor):
SettingsWindowController controller = new SettingsWindowController();
FXMLLoader loader = new FXMLLoader(SettingsWindowController.class
.getResource("Settings.fxml"));
loader.setController(controller);
AnchorPane page = (AnchorPane)loader.load();
Try this :
FXMLLoader fxmlLoader = FXMLLoader(SettingsWindowController.class.getResource("Settings.fxml"));
AnchorPane page = (AnchorPane) fxmlLoader.load();

Categories