JavaFX: 3 Ways of Passing Information Between Scenes!
Tags: java, javafx, tutorial, programming
Published: 2020-07-02 19:52:16

One of the most common issues that raises when developing a desktop application with JavaFX is "How can I pass this user input from scene A to scene B?", while you can always rely on text files or even databases, these may not be the most suitable approach.

The _goal_ of this tutorial is to teach you **three** different ways you can pass information from one scene to another. Before we dive deep on that, let's first make a few assumptions:

- We have a JavaFX app with two _fxml_ files, **SceneA** and **SceneB**, each with its own controller, and we want to pass data from A to B.
- We have a class that encapsulates the information we want. For the sake of this post, let's say this class is defined as follows:
![UML User Class Diagram](https://dev-to-uploads.s3.amazonaws.com/i/3epi4z99jteazm708gy4.png)
- We have a method named `sendData` in the **SceneAController** where we gather the information. This method is called upon a `mouseClicked` event
- We have a method named `receiveData` in the **SceneBController** where we populate an instance of the user class with the information we receive. This method is called upon a `mouseClicked` event

That's all 👍! Now about those methods...

## First Method: Using the UserData function
In JavaFX, all the classes that inherit from the class **Node** have the following methods: `setUserData(Object)` and `getUserData()`. According to the official documentation, these methods allow us to attach an arbitrary object to a node for later use. I think you can see how powerful is that! Although we can use any node for this purpose, I recommend you use the **stage** itself, since it's the same no matter the scene.

In order to use this method, in the `sendData` function, follow these steps:

1. Save the information in an instance of the user class
2. Grab the node representing the button from the `event` object
3. Get the instance of the **stage** from the node and close it
4. Load the scene through the `FXMLLoader` class
5. Pass the information to the stage using the `setUserData` function
6. Create a **new scene** and pass it to the stage
7. Make the stage visible again

The `sendData` function should look something like this:
{% gist https://gist.github.com/DevTony101/8084cec59dbd13371902329b36de935b %}

In the `receiveData` function the only thing we have to do is:

1. Get the instance of the **stage** just like before
2. Recover the object using the `getUserData` function
3. Use the information as you see fit

Hence, the `receiveData` function should look something like this:
{% gist https://gist.github.com/DevTony101/6ee98414c99b6ef7534e3bec304982db %}

And just like that we have managed to pass information between the two scenes, ¡Bravo 🎉!. This approach is very useful when we need a quick way to send data back and forth but, what if we need to pass more than one object? We will see how to overcome this in the next section.

## Second Method: Manually Setting the Controllers
Usually when we create our _fxml_ files, the **IDE** automatically creates a controller for it and link them together using the following property in the root tag of the _fxml_ file:
```
fx:controller="<package>.Controller"
```
In addition, this also creates a new instance of the controller class, but if we want to pass information to a field stored in the controller, like we would in a regular class, we must create the instance manually.

In order to use this method, we need to follow these steps:

1. Remove the property we saw earlier from the `SceneB.fxml` file
2. In the **SceneBController**, create a new attribute of type user along with its `set` and `get` function

Back in the `sendData` function:

1. Follow the first three steps we saw in the previous section
2. Create an `FXMLLoader` object and store in it the result of the statement `FXMLLoader.load(...)`
3. Create a new instance of the **SceneBController** class and pass it the information using the `set` method you created
4. Use the `setController` method in the `FXMLLoader` object you created and pass it the controller instance
5. Use the `load` method and store its result in the `root` object, the rest is the same as before

The `sendData`  function should look something like this:

{% gist https://gist.github.com/DevTony101/a56c3849cbb97e51b2651493d3c7b4ec %}

Now in the `receiveData` function you can display the information stored in the user field, like this:

{% gist https://gist.github.com/DevTony101/bbe58febec8bd701c5d62d5cbe013dcf %}

This method sure is more complex than the last one, but now you can pass as much objects as you like between the two scenes.

## Third Method: Using a Singleton Class
Until now, we have relied on the controllers for passing the information, but if we truly want to mimic the business logic we would do if we were using a database for example, we can create a third class from which the two controllers can access. In order to do that, the controllers **must** share the same instance of the new class, and we can accomplish that using the **Singleton** pattern.

There are several ways we can implement this pattern, but the most simple one is by doing the following:

1. Create a class and make its constructor private, so new instances can't be created
2. Create a constant of the same type as the class and initialize it
3. Create a public static function to retrieve said constant

In addition to these steps, you also need to create a field of the class type you are interested in, in this case is user, along with its `set` and `get` functions. For the sake of this tutorial, let's say we create a class named `UserHolder` and follow the steps, this would be the result:

{% gist https://gist.github.com/DevTony101/8d5e69f6c9e5004fdd287e37042af106 %}

Back in the `sendData` function:

1. Follow the first 4 steps of the first section
2. Grab the static instance of the UserHolder class
3. Pass the information using the `set` function you created
4. The rest is the same as before

{% gist https://gist.github.com/DevTony101/1bcb87b75877a2337eda7a76439cfb36 %}

And lastly in the `receiveData` function, you just need to recover the object from the static instance, like this:

{% gist https://gist.github.com/DevTony101/f845e3b59b4c854ee1656aa83cf7d7ec %}

And with a very few steps, we have managed to share information between the scenes through a singleton class. This approach is particularly useful when doing a _configuration_ view, you can store in the singleton class the user's preferences and easily recover them anywhere in your program.

## Final Thoughts
In this post, we learned how to pass information from a **scene A** to a **scene B** in three different ways, and we saw how we would implement this in our code as well as some use case where you might need them. I hope you have found this useful and want to thank you for your time.

Until next time 👋!