Java Arena
Step 3 of 8

One frame, changing content

setScene swaps everything in the window. Many applications keep part of the window in place instead, such as a menu along the top, and change only the area under it. A BorderPane (module 48) fits that well: the menu goes in the top region, the content in the center, and a handler swaps the center with setCenter.

A guide with a menu

A castle's visitor guide has three pages, chosen from a menu:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) {
        Label hall = new Label("The great hall seats 200 guests under an oak roof.");
        Label tower = new Label("The north tower has 147 steps and a view over the river.");
        Label kitchens = new Label("The kitchens once baked bread for the whole village.");

        Button toHall = new Button("Great hall");
        Button toTower = new Button("Tower");
        Button toKitchens = new Button("Kitchens");
        HBox menu = new HBox(10, toHall, toTower, toKitchens);
        menu.setPadding(new Insets(10));

        BorderPane frame = new BorderPane();
        frame.setTop(menu);
        frame.setCenter(hall);

        toHall.setOnAction(event -> frame.setCenter(hall));
        toTower.setOnAction(event -> frame.setCenter(tower));
        toKitchens.setOnAction(event -> frame.setCenter(kitchens));

        stage.setScene(new Scene(frame));
        stage.setTitle("Castle guide");
        stage.show();
    }

    public static void main(String[] args) {
        launch(Main.class);
    }
}
The window

After: Click "Tower"

This window is wider than the screen: scroll it sideways, or read it as text below.

The window as text
Window "Castle guide"
  BorderPane
    top: HBox spacing 10, padding 10
      Button "Great hall"
      Button "Tower"
      Button "Kitchens"
    center: Label "The north tower has 147 steps and a view over the river."
  • The three pages are made at the start and kept in variables. Only one of them is in the window at a time: the center region holds one node, and setCenter puts another one in its place.
  • The page that is taken out isn't destroyed. The variable still refers to it, and the next click on its button puts it back.
  • start calls frame.setCenter(hall) before the window shows, so the guide opens on a page and not on an empty middle. A view the user sees first is the default view.
  • The menu, the scene and the stage stay the same the whole time. Only the center changes.

Pages with more in them

A page can be any node, so it can be a whole layout with its own buttons and handlers. The front desk of the castle uses the guide to sell tickets too. Its pages are built by helper methods (module 48), once each:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {
    private int tickets;

    @Override
    public void start(Stage stage) {
        VBox hall = hallPage();
        VBox sales = ticketPage();

        Button toHall = new Button("Great hall");
        Button toTickets = new Button("Tickets");
        HBox menu = new HBox(10, toHall, toTickets);
        menu.setPadding(new Insets(10));

        BorderPane frame = new BorderPane();
        frame.setTop(menu);
        frame.setCenter(hall);
        toHall.setOnAction(event -> frame.setCenter(hall));
        toTickets.setOnAction(event -> frame.setCenter(sales));

        stage.setScene(new Scene(frame));
        stage.setTitle("Castle front desk");
        stage.show();
    }

    private VBox hallPage() {
        VBox page = new VBox(6, new Label("The great hall seats 200 guests."), new Label("Open daily from 10 to 17."));
        page.setPadding(new Insets(10));
        return page;
    }

    private VBox ticketPage() {
        Label sold = new Label("Tickets sold today: 0");
        Button sell = new Button("Sell a ticket");
        sell.setOnAction(event -> {
            this.tickets++;
            sold.setText("Tickets sold today: " + this.tickets);
        });
        VBox page = new VBox(6, sold, sell);
        page.setPadding(new Insets(10));
        return page;
    }

    public static void main(String[] args) {
        launch(Main.class);
    }
}
The window

After: Click "Tickets", click "Sell a ticket", click "Sell a ticket", click "Great hall", then click "Tickets"

This window is wider than the screen: scroll it sideways, or read it as text below.

The window as text
Window "Castle front desk"
  BorderPane
    top: HBox spacing 10, padding 10
      Button "Great hall"
      Button "Tickets"
    center: VBox spacing 6, padding 10
      Label "Tickets sold today: 2"
      Button "Sell a ticket"

The ticket page was out of the window for a while, but it comes back as it was, with Tickets sold today: 2: it's the same VBox with the same label. The window as text shows the page indented under center:, with its own children under it.

setScene or setCenter?

Both switch views, and they fit different windows:

  • stage.setScene(...) replaces everything in the window. It suits views that share nothing, such as a login form and the program behind it, or step 1's settings.
  • frame.setCenter(...) keeps the rest of the BorderPane: a menu in the top region, a status line at the bottom. It suits an application whose views are always one click away.

Your task

Challenge 1 of 3

A funfair's info screen. The four pages (labels) and the four menu buttons are made already, and so is an empty BorderPane. Finish the window:

  • top: an HBox with the spacing 10 and the padding 10 on every side, holding the buttons Rides, Food, Hours and Prices, in that order
  • center: the page of the button clicked last: Rides shows The roller coaster reopens on Friday., Food shows Pancakes and soup by the big wheel., Hours shows Open daily from 10 to 20., and Prices shows One ride costs 4 tokens.
  • at the start, the center shows the rides page

The window's title is Funfair. The task card shows the window after a click on Food.

Challenge 2

A city bike app has a menu that shows its pages in the center of a BorderPane. Make the menu show where the user is: the button of the page that is showing is disabled, and the other two are enabled. setDisable(true) disables a button, and setDisable(false) enables it again (module 49). A disabled button does nothing when it's clicked.

The app opens on the prices page, so Prices starts disabled. A click on Stations shows the stations page, disables Stations and enables the other two, and so on. Don't change anything else: the pages, the menu and the texts stay as they are. The task card shows the window after a click on Stations.

Challenge 3

A guide with two pages and a Next button that switches between them. The program clicks the button itself with fire(), and getParent() returns the pane a node is in, or null when it isn't in one. What does it print?