How to Pass Values to Window in JavaFX - java

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();

Related

Cannot seem to instantiate a non-null FXMLLoader

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().

Why I can't pass values with controllers and to display in scene?

This is the controller to set text to label.
#FXML
private Label label1;
public void two(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("window2.fxml"));
Scene switchEdit = new Scene(root);
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.setScene(switchEdit);
stage.show();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void initData(String title) {
label1.setText(title);
}
}
This is the controller to get the value needed for the label1. I alreay made an object and call the method on the first controller to pass the value from the textfield.
#FXML
private TextField txt;
public void goBack(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
Parent roo = FXMLLoader.load(getClass().getResource("window.fxml"));
Scene chEdit = new Scene(roo);
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
controller2 control = loader.getController();
control.initData(txt.getText());
stage.setScene(chEdit);
stage.show();
}
}
I already watched multiple tutorials but nothing works!
You load the fxml via the static FXMLLoader.load(URL) method instead of using the FXMLLoader instance to load the fxml.
Change
FXMLLoader loader = new FXMLLoader();
Parent roo = FXMLLoader.load(getClass().getResource("window.fxml"));
to
FXMLLoader loader = new FXMLLoader(getClass().getResource("window.fxml"));
Parent roo = loader.load();
Of course this also requires the fx:controller attribute to be specified in the root element of window.fxml. It's value should be the fully qualified name of your controller2 class.
PS: Consider adhering to the java naming conventions and use type names starting with an uppercase letter.

Inflating FXML from subdirectory

I have a Launcher class which I want to use to open a new window.
From main in Launcher, I'm calling :
ChatList chatList = new ChatList(communicator);
The constructor of ChatList calls method showChatList() where I try to inflate a FXML document:
private void showChatList() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/ChatList.fxml"));
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
However I'm getting a java.lang.IllegalStateException: Location is not set. where I'm calling fxmlLoader.load(). My project file structure is as follows:
I've tried putting in an absolute file path to the FXML file but still had no luck.
Can anyone help me understand what the general principle is behind inflating FXMLs in JavaFX (with multiple stages) or point me to a good resource that they've come across.
Cheers.
I know this is an old question, but maybe can help someone .
You have to write all the path of the fxml.
In your case is:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/client/fxml/ChatList.fxml"));
Another example:
Youproject/Src/parentpackage/childpackage/fxmlToGet.fxml
If you want to get the fxml in childpackage you have to write:
FXMLLoader(getClass().getResource("/parentpackage/childpackage/fxmlToGet.fxml"));

Java FX changing value of Label from different scene

I have two scenes. The first scene invokes second scene using the following code.
#FXML
private void confirmation(ActionEvent event) throws IOException{
Stage confirmation_stage;
Parent confirmation;
confirmation_stage=new Stage();
confirmation=FXMLLoader.load(getClass().getResource("Confirmation.fxml"));
confirmation_stage.setScene(new Scene(confirmation));
confirmation_stage.initOwner(generate_button.getScene().getWindow());
confirmation_stage.show();
}
There is a label in "Confirmation.fxml" called "Proceed".
I need to change the content of that label from within this function and return the result(true/false). Help?
Create a ConfirmationController for the FXML. From the controller, expose a method which allows you to pass data (string) to set to the label.
public class ConfirmationController implements Initializable {
...
#FXML
private Label proceed;
...
public void setTextToLabel (String text) {
proceed.setText(text);
}
...
}
Inside your method where you are loading the FXML, you can have :
...
FXMLLoader loader = new FXMLLoader(getClass().getResource("Confirmation.fxml"));
confirmation = loader.load();
ConfirmationController controller = (ConfirmationController)loader.getController();
controller.setTextToLabel("Your Text"); // Call the method we wrote before
...
Labels in FXML have a setText method. So for your case the "Proceed" label will look something like:
Proceed.setText("The new text");
As for the second part of the question, I'm not 100% sure as to what you are asking. I don't really see any case for the function to return true or false.
Assuming that you have a controller called:confirmation_controller.java'. inside that controller, you have a public method getProceedLabel() that returns a reference for the label called Proceed. you can try the following code:
Stage confirmation_stage;
Parent confirmation;
confirmation_stage=new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Confirmation.fxml"));
confirmation = loader.load();
confirmation_controller controller = loader.getController();
Label label = controller.getProceedLabel();
label.setText("..."):
confirmation_stage.setScene(new Scene(confirmation));
confirmation_stage.initOwner(generate_button.getScene().getWindow());
confirmation_stage.show();

Reloading an Already Populated AnchorPane

So I have been working on a JavaFX project where I have a pretty simple work flow. I have several different AnchorPanes that I use, on each the user will fill out some information and go on to the next AnchorPane. Whenever they move on to the next AnchorPane I load the new AnchorPane using the following code.
private Initializable replaceSceneContent(String fxml) throws Exception {
FXMLLoader loader = new FXMLLoader();
InputStream in = MyClass.class.getResourceAsStream(fxml);
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(Caster.class.getResource(fxml));
AnchorPane page;
try {
page = (AnchorPane) loader.load(in);
} finally {
in.close();
}
Scene scene = new Scene(page, APP_WIDTH, APP_HEIGHT);
stage.setScene(scene);
stage.sizeToScene();
return (Initializable) loader.getController();
}
This loads everything fine. But I also have the ability to go back to the previous AnchorPane. Currently this uses the same method, but this is not ideal as it loads a brand new AnchorPane and all the information that user had previously entered is gone. I would like to persist the anchorpanes and reload them and have tried to reload them using code similar to the following
private void replaceSceneContent(AnchorPane page) throws Exception {
Scene scene = new Scene(page, APP_WIDTH, APP_HEIGHT);
stage.setScene(scene);
stage.sizeToScene();
}
However, this results in a totally white screen on my application, maybe because I am not loading the FXML again? I need some ideas on how to persist the data the users entered if they want to go back. Any ideas on how to do this well?

Categories