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);
}
Related
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().
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) {
}
}
I would like to communicate with a FXML controller class at any time, to update information on the screen from the main application or other stages.
Is this possible? I havent found any way to do it.
Static functions could be a way, but they don't have access to the form's controls.
Any ideas?
You can get the controller from the FXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();
store it in your main stage and provide getFooController() getter method.
From other classes or stages, every time when you need to refresh the loaded "foo.fxml" page, ask it from its controller:
getFooController().updatePage(strData);
updatePage() can be something like:
// ...
#FXML private Label lblData;
// ...
public void updatePage(String data){
lblData.setText(data);
}
// ...
in the FooController class.
This way other page users do not bother about page's internal structure like what and where Label lblData is.
Also look the https://stackoverflow.com/a/10718683/682495. In JavaFX 2.2 FXMLLoader is improved.
Just to help clarify the accepted answer and maybe save a bit of time for others that are new to JavaFX:
For a JavaFX FXML Application, NetBeans will auto-generate your start method in the main class as follows:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Now, all we need to do to have access to the controller class is to change the FXMLLoader load() method from the static implementation to an instantiated implementation and then we can use the instance's method to get the controller, like this:
//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;
#Override
public void start(Stage stage) throws Exception {
//Set up instance instead of using static load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
//Now we have access to getController() through the instance... don't forget the type cast
myControllerHandle = (MyController)loader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Another solution is to set the controller from your controller class, like so...
public class Controller implements javafx.fxml.Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
// Implementing the Initializable interface means that this method
// will be called when the controller instance is created
App.setController(this);
}
}
This is the solution I prefer to use since the code is somewhat messy to create a fully functional FXMLLoader instance which properly handles local resources etc
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}
versus
#Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("/sample.fxml");
FXMLLoader loader = createFXMLLoader(location);
Parent root = loader.load(location.openStream());
}
public FXMLLoader createFXMLLoader(URL location) {
return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}
On the object's loading from the Main screen, one way to pass data that I have found and works is to use lookup and then set the data inside an invisible label that I can retrieve later from the controller class. Like this:
Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData);
This works, but there must be a better way.
I would like to communicate with a FXML controller class at any time, to update information on the screen from the main application or other stages.
Is this possible? I havent found any way to do it.
Static functions could be a way, but they don't have access to the form's controls.
Any ideas?
You can get the controller from the FXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();
store it in your main stage and provide getFooController() getter method.
From other classes or stages, every time when you need to refresh the loaded "foo.fxml" page, ask it from its controller:
getFooController().updatePage(strData);
updatePage() can be something like:
// ...
#FXML private Label lblData;
// ...
public void updatePage(String data){
lblData.setText(data);
}
// ...
in the FooController class.
This way other page users do not bother about page's internal structure like what and where Label lblData is.
Also look the https://stackoverflow.com/a/10718683/682495. In JavaFX 2.2 FXMLLoader is improved.
Just to help clarify the accepted answer and maybe save a bit of time for others that are new to JavaFX:
For a JavaFX FXML Application, NetBeans will auto-generate your start method in the main class as follows:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Now, all we need to do to have access to the controller class is to change the FXMLLoader load() method from the static implementation to an instantiated implementation and then we can use the instance's method to get the controller, like this:
//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;
#Override
public void start(Stage stage) throws Exception {
//Set up instance instead of using static load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
//Now we have access to getController() through the instance... don't forget the type cast
myControllerHandle = (MyController)loader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Another solution is to set the controller from your controller class, like so...
public class Controller implements javafx.fxml.Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
// Implementing the Initializable interface means that this method
// will be called when the controller instance is created
App.setController(this);
}
}
This is the solution I prefer to use since the code is somewhat messy to create a fully functional FXMLLoader instance which properly handles local resources etc
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}
versus
#Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("/sample.fxml");
FXMLLoader loader = createFXMLLoader(location);
Parent root = loader.load(location.openStream());
}
public FXMLLoader createFXMLLoader(URL location) {
return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}
On the object's loading from the Main screen, one way to pass data that I have found and works is to use lookup and then set the data inside an invisible label that I can retrieve later from the controller class. Like this:
Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData);
This works, but there must be a better way.
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 ;
}