Functional Interfaces

What is a functional interface? And what good are Lambdas?

Copy this into a file named MenuDemo.java.

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.BorderPane;
public class MenuDemo extends Application
{
    public MenuDemo()
    {
    }
    @Override
    public void init()
    {
    }
    @Override
    public void start(Stage primary)
    {
        BorderPane bp = new BorderPane();

        primary.setScene(new Scene(bp, 400,400));
        primary.setTitle("MenuDemo");
        primary.show();
    }
    @Override
    public void stop()
    {
    }
    //Main is actually optional.
    public static void main(String[] args)
    {
        launch(args);
    }
}

Begin by importing "the trinity" for menus.

import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;

Now add this to the constructor and insert a state variable for the menu bar.

MenuBar mbar;
public MenuDemo()
{
    mbar = new MenuBar();
}

To avoid an excessively long start methods, ww will create a private method for building the menus.

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.BorderPane;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
public class MenuDemo extends Application
{
    MenuBar mbar;
    public MenuDemo()
    {
        mbar = new MenuBar();
    }
    @Override
    public void init()
    {
    }
    @Override
    public void start(Stage primary)
    {
        BorderPane bp = new BorderPane();
        createMenus();
        primary.setScene(new Scene(bp, 400,400));
        primary.setTitle("MenuDemo");
        primary.show();
    }
    @Override
    public void stop()
    {
    }
    private void createMenus()
    {
    }
    //Main is actually optional.
    public static void main(String[] args)
    {
        launch(args);
    }
}

Now we got to work on the createMenus() method.

private void createMenus()
{
    Menu fileMenu = new Menu("File");
    Menu editMenu = new Menu("Edit");
    mbar.getMenus().addAll(fileMenu, editMenu);
}

We also need to get the menu bar into the window. We use the BorderPane's setTop method.

@Override
public void start(Stage primary)
{
    BorderPane bp = new BorderPane();
    bp.setTop(mbar);
    createMenus();
    primary.setScene(new Scene(bp, 400,400));
    primary.setTitle("MenuDemo");
    primary.show();
}

Compile and run. You will see this.

picture of window with menus in it

Next, we create menu items and we get them into the menus.

    private void createMenus()
    {   
        Menu fileMenu = new Menu("File");
        Menu editMenu = new Menu("Edit");
        mbar.getMenus().addAll(fileMenu, editMenu);
        MenuItem newItem = new MenuItem("New");
        MenuItem openItem = new MenuItem("Open...");
        MenuItem saveItem = new MenuItem("Save");
        MenuItem saveAsItem = new MenuItem("Save As...");
        MenuItem quitItem = new MenuItem("Quit");
        fileMenu.getItems().addAll(newItem, openItem, saveItem, saveAsItem, quitItem);
        MenuItem copyItem = new MenuItem("Copy");
        MenuItem pasteItem = new MenuItem("Paste");
        MenuItem cutItem = new MenuItem("Cut");
        MenuItem selectAllItem = new MenuItem("Select All");
        editMenu.getItems().addAll(copyItem, pasteItem, cutItem, selectAllItem);
    }

Now click on the menus and see your shiny new menu items appear! Can you draw the scene graph now?

Now let's add a text area.

MenuBar mbar;
TextArea ta;
public MenuDemo()
{
    mbar = new MenuBar();
    ta = new TextArea();
}

Then, install the text area into the window with this.

 bp.setCenter(ta);

Next, propitiate the import police.

import javafx.scene.control.TextArea;

picture of window with menus and text earea in it

putText.setOnAction(e -> "tf.setText("Hey, look at me!"));
putText.setOnAction(e -> "tf.setText("Hey, look at me!"));
putText.setOnAction(e -> "tf.setText("Hey, look at me!"));
putText.setOnAction(e -> "tf.setText("Hey, look at me!"));

here is what happened.

  1. putText is a button, so it has a setOnAction method.
  2. setOnAction expects one argument, an argument of type EventHandler<ActionEvent>.
  3. EventHandler<ActionEvent> is a functional interface; it specifies one methood, void handle(ActionEvent e).
  4. Type inference occurs: An anonymous object of type EventHandler<ActionEvent> is created and its handle method is taken to be the lambda.

Magic demystified. This new style of event handling reduces the boilerplate code that adds nothing to the meaning of programs. This innovation is also great when using the new Stream API.