Switching to Different Screens in JavaFX and FXML


Often times you need to write an application that switches to another screen (or “Scene” as we say in Java-FX). Remember how Java-FX programs are laid out – the Stage holds a Scene, the Scene holds a root or main container, like a Flow, Grid, Border, Stack or Anchor pane. The root container holds everything else, which could include other nested containers. If we build up more than 1 scene, we can ask the stage to set its scene to another one when we need it to. In FXML we can draw out 2 different scenes (as 2 separate FXML files rather than create them with code.
javafxmultiscreen1
javafxmultiscreen2

 

Switching Scenes Java-FX Style

1 – Declare Objects Needed

We are going to need 2 of everything:  Buttons, Labels, FlowPanes and Scenes.  We also need a Stage variable.

public class TwoScene extends Application {
    Button btnscene1, btnscene2;
    Label lblscene1, lblscene2;
    FlowPane pane1, pane2;
    Scene scene1, scene2;
    Stage thestage;

 2 – Build Objects in Start

Notice the first line in “start”.  I am getting a reference to “primaryStage” – which is sent in as a parameter – and copying it to “thestage”, so I can use it in other parts of the program later.  The rest of the code is pretty standard.

  @Override
    public void start(Stage primaryStage) {
      
        thestage=primaryStage;
        //can now use the stage in other methods
       
        //make things to put on panes
        btnscene1=new Button("Click to go to Other Scene");
        btnscene2=new Button("Click to go back to First Scene");
        btnscene1.setOnAction(e-> ButtonClicked(e));
        btnscene2.setOnAction(e-> ButtonClicked(e));
        lblscene1=new Label("Scene 1");
        lblscene2=new Label("Scene 2");

 3 – Build 2 Panes

Each Scene needs a root container so I have 2 FlowPanes that will work.  I use java-fx style to give each one padding and a different color to tell them apart.  I can also set the vertical gap between the buttons and labels.  Then I add the controls to their proper pane/container.

     //make 2 Panes
     pane1=new FlowPane();
     pane2=new FlowPane();
     pane1.setVgap(10);
     pane2.setVgap(10);
     //set background color of each Pane
     pane1.setStyle("-fx-background-color: tan;-fx-padding: 10px;");
     pane2.setStyle("-fx-background-color: red;-fx-padding: 10px;");
        
     //add everything to panes
     pane1.getChildren().addAll(lblscene1, btnscene1);
     pane2.getChildren().addAll(lblscene2, btnscene2);

4 – Create 2 Scenes

With 2 Panes I can make a separate Scene for each one.  The first scene gets set as the initial scene since the stage can only show 1 scene at a time.

        //make 2 scenes from 2 panes
        scene1 = new Scene(pane1, 200, 100);
        scene2 = new Scene(pane2, 200, 100);
        
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene1);
        primaryStage.show();
    }

 5 – Code for ButtonClicked

This is the grand finale – using the stage’s ‘setScene’ method I can easily switch from 1 scene to the other.  Thanks to the 1st line in the start() method I now have a reference to the stage down here.

 public void ButtonClicked(ActionEvent e)
    {
        if (e.getSource()==btnscene1)
            thestage.setScene(scene2);
        else
            thestage.setScene(scene1);
    }

Switching Scenes FXML Style

1 – Design the First Scene

Using the existing FXML document you are given, just put a label and a button on it – couldn’t be easier.   Yes, we used a FlowPane in the FX version, but the AnchorPane will work just fine for this example.

 Screen Shot 2015-01-16 at 5.57.38 AM

2 – Arrange Controls

Not much to do here, just place them where you want them (much more straight-forward than coding it into a FlowPane)

Screen Shot 2015-01-16 at 5.57.31 AM

3 – Add Color If You Wish

Click on the Anchor Pane and go to properties (right side). Drop-down the color setting and set it.  Also very easy.  Save when you are done.

 Screen Shot 2015-01-16 at 5.57.51 AM

4 – Add a New FXML Document

Back in NetBeans, you can add a new Empty FXML document.  Here is where things are quite different than the FX version as you are working with another file, rather than coding 2 Panes and Scenes in one FX document.

 Screen Shot 2015-01-15 at 6.50.53 PM

5 – Point the new FXML document to the Existing Controller

This is step 3 in creating the new document and it is very important.  In order to have the new FXML document rely on the same controller as the OTHER FXML document, you need to set that up here.

6 – Design A Similar FXML Document

No picture needed for this step here.  You can create a simple button/label document just like the original one, and set the color of the AnchorPane too if you want to.

 Screen Shot 2015-01-16 at 5.55.28 AM

7 – Declare @FXML Control Variables in the Controller

We only need to make @FXML references to the 2 buttons since we don’t need to ‘talk’ to the labels in our code.  Even though the buttons are on different FXML documents, they can share the same controller.

public class FXMLDocumentController implements Initializable {
    
    @FXML
    private Button btn1;
    @FXML
    private Button btn2;

8 – Complete handleButtonAction Method

Both buttons will run this method when they are clicked on, even though they are on different controllers.  Since this method is attempting to load FXML documents, it needs to “throws IOException” in case it can’t find the document when it tries to open it.

  • Here’s the trick – we can ASK a button to give us a reference to the STAGE it is on by asking for the Scene and the Scene’s window – which also happens to be the stage.
  • From there we load the appropriate FXML document into a generic Parent object and ‘make a Scene’ with it.
  • Lastly, like the JavaFX version we ask the stage to set the scene to the new scene.
 @FXML
 private void handleButtonAction(ActionEvent event) throws IOException{
     Stage stage; 
     Parent root;
     if(event.getSource()==btn1){
        //get reference to the button's stage         
        stage=(Stage) btn1.getScene().getWindow();
        //load up OTHER FXML document
  root = FXMLLoader.load(getClass().getResource("FXML2.fxml"));
      }
     else{
       stage=(Stage) btn2.getScene().getWindow();
  root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
      }
     //create a new scene with root and set the stage
      Scene scene = new Scene(root);
      stage.setScene(scene);
      stage.show();
    }

9 – Go Back To Each FXML Document to Complete the Buttons

Now that you have declared the @FXML buttons in the controller, you can come back to each FXML document and connect each button to its ID.  You also have to connect each button to its On-Action method, which is the same method for both buttons.

 Screen Shot 2015-01-16 at 5.58.06 AM

The YouTube Video

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>