JavaFX, Label null pointer exception - javafx

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.

Related

JavaFX: Call function on controller when corresponding stage is closed

Is there a way to trigger a function in a controller, when the stage containing the view connected to the controller is closed? Let’s say I want to call a “cleanup” function (e.g. save changes) on every controller in my stage, when the window is closed.
Typically you put the content of the FXML file into a stage (via a scene) externally to the FXML and controller. So you should add code where you actually have access to the stage to do this. You can define a method in your controller class to invoke when you need to do the "cleanup":
public class Controller {
// injected fields, etc...
public void initialize() {
// initialization code...
}
// event handlers, etc...
public void shutdown() {
// cleanup code here...
}
}
Now when you load the FXML and display its content in a window, you can register a handler with the stage that invokes the controller's shutdown method:
Stage stage = ... ;
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml/file"));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
// cleanup controller resources when window closes:
Controller controller = loader.getController();
stage.setOnHidden(e -> controller.shutdown());
stage.show();
You can use Window.setOnHidden

JavaFX exchange data between controllers (parent/child forms)

Is this approach lame to do so?
I've tried many approaches e.g.
How can I exchange data between forms
JavaFX pass values from child to parent
JavaFX 2.2 -fx:include - how to access parent controller from child controller
but this seems to be pretty direct and understandable.
public class ParentController {
private Settings settings;
public void setSettings(Settings settings) {
this.settings = settings;
System.out.println(this.settings.toString());
}
#FXML
private Button open;
#FXML
private void pass() throws IOException {
Stage st = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Child.fxml"));
Region root = (Region) loader.load();
Scene scene = new Scene(root);
st.setScene(scene);
ChildController controller = loader.<ChildController>getController();
controller.initialize(this);
st.show();
}
}
public class ChildController {
#FXML
private TextField number; // some settings
#FXML
private Button ok;
private ParentController parentController ;
#FXML
public void pass() {
Stage stage = (Stage) ok.getScene().getWindow();
parentController.setSettings(setSettings());
stage.close();
}
private Settings setSettings(){
return new Settings(Integer.valueOf(this.number.getText()));
}
public void initialize(ParentController parentController) {
this.parentController = parentController;
}
}
In such the way I'm getting settings object generated in Child controller and pass this object to the parent controller.
This works...
Is this approach appropriate? If not, what pitfall is may imply?
The question is probably too opinion-based for this forum. The trade-off for the simplicity you gain (compared to, say, JavaFX pass values from child to parent) is that you have tightly-coupled the child to the parent: in other words you can't use the child view/controller in any context where you don't have that specific parent. In the linked approach, the child view/controller have no dependency on the parent. Whether or not this is desirable/beneficial/worth the added complexity will depend on your exact use case.
I thought it was appropriate. for me it was just a coding style.
but in my opinion , change your settings variable to public static, stored in the Main class and initialized in the Main class, to be accessible at all controllers or other classes. thats my style :D
public static settings Settings;
Main.settings.( Something)
Happy coding..

javafx - how to get reference to main Stage in MainController in initialize() method?

I need to get reference to main Stage of app in initialize() method in MainController. I tried using this solution:
...
#FXML private Label label;
...
// in some method block
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
but other label (or other controlls) doesn't exist when application call initialize() and it returns NullPointerException. How to avoid this?
Greetings

How to access application from controller in javafx

How can I access javafx Application class from a Controller class? If I go into more specific I need to keep one stage and switch scenes.
You can call the following on an arbitrary node of your scene to get the current stage.
Node.getScene().getWindow()
It will give you an object from type Window. (Stage subclasses Window)
Or you hand over the stage from outside of the controller:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"Main.fxml"));
fxmlLoader.setRoot(this);
MainController controller = new MainController()
controller.setStage(stage);
fxmlLoader.setController(controller);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}

Stuck with event handling Java FX - Controller - Scene builder

I want to use Netbeans Java FX with Scene builder for a measurement application. I have designed a scene with controls. I can handle the events from the UI-controls within the '...Controller.java'.
The 'controller' is the standard piece of code that is referenced in the XML file and gets initialized by the system with:
public void initialize(URL url, ResourceBundle rb) { ..
My problem: how do I access my central, persisting, 'model' objects from within the controller? Or, to be more exact, from the event handlers created within the controller initialize function.
The 'model' object would be created within the application object.
The solution must be trivial, but I have not found a way to
either access the Application from the controller
or access the controller from within the Application.
What am I missing?
(the next question would be how to access the tree of panes within the object hierarchy created by screen builder, e.g. for graphics manipulation on output. Since the objects are not created by own code I can not store references to some of them. Ok, they could perhaps be found and referenced by tree-walking, but there must be a better way!)
Thanks for all insights!
I have used the 2nd approach (access the controller from within the Application) for awhile ago similar to following. In Application class:
//..
private FooController fooController;
private Pane fooPage;
private Model myModel;
#Override
public void start(Stage stage) {
//..
myModel = new Model();
getFooController().updateModel(myModel);
//..
Button button = new Button("Update model with new one");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Model myNewModel = new Model();
getFooController().updateModel(myNewModel);
}
}
// create scene, add fooPage to it and show.
}
private FooController getFooController() {
if (fooController == null) {
FXMLLoader fxmlLoader = new FXMLLoader();
fooPage = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
fooController = (FooController) fxmlLoader.getController();
}
return fooController;
}
Actually the first and second parts of your question is answered JavaFX 2.0 + FXML. Updating scene values from a different Task to the similar question of yours.

Resources