Java FX – GUIs
TOPIC 02 – HANDLING EVENTS

 

 

LESSON NOTE

 

 

EVENTS

 

In computer science, an event occurs when a control is triggered in some way.  The most common example, is when a button is clicked.  Another example would be when the <Enter> key is hit inside of a TextField.

 

RESONPONDING TO EVENTS

 

Computer programs often need to respond to an event when they occur.  This is called event driven programming.  In this lesson, we will learn how to make Java respond to events.

 

EVENT HANDLER

 

An event handler is an object that takes care of responding to an event.  For example, when a button is clicked, the event handler is responsible for the response.  Essentially, the event handler contains a method in it that gets executed each time an event occurs. 

 

THE HANDLE METHOD

 

For Java FX, our event handler class needs to implement the EventHandler interface.  This forces our class to have the following method in it:

 

    public void handle(ActionEvent e)

 

It is inside this method that we will write the code to respond to the event.  For example, if the event was a button click, perhaps we would make some text appear in a text field, or perhaps we would open or close a window.

 

ALL IN ONE CLASS

 

We can make a separate class from our Application class deal with handling events.  However, this has one big disadvantage: That class doesn't have access to the data fields of our Application class.  So we would have to find a way to communicate between the two classes.  That is certainly possible, but at least for now, it's easier to place the handle method inside the same class as our Application class. 

 

So this gives us the setup below.  Our class extends Application and implements EventHandler.  The events it deals with are ActionEvent objects so we specify that.  That class contains both the start and the handle methods.  Note that the setup below doesn't show the main method that might be required depending on your IDE.

 

public class FirstApplication extends Application implements     EventHandler<ActionEvent>

{

     public void start(Stage primaryStage) throws Exception

     {

       //Create the GUI look here

     }

 

     public void handle(ActionEvent e)

     {

       //Handle events here

     }

}

 

 

CONTROLS AS DATA FIELDS

 

In order the code in the handle method to have access to the controls in the start method, we need to make the controls datafields.  We simply declare each control above the start method and create each inside start. 

 

 

EXAMPLE 1 – CONSOLE HELLO

 

The following window includes the handle method that is executed when the button is clicked.  The method simply displays "Hello there." in the console.

 

 

 

NEW CODE EXPLANATION

 

The class now implements the EventHandler interface for ActionEvents.  So we add the following to the end of the class declaration:

 

     implements EventHandler<ActionEvent>

 

Doing the above forces us to include the handle method.  Inside that method, we will simply output a message to the console.

 

     public void handle(ActionEvent e)

     {

        System.out.println("Hello there.");

     }

 

Before we can make this work though, we have to specify that this class will listen for events related to the button.   So, inside the start method, we need the line:

 

     b1.setOnAction(this); 

 

Also, notice that the Button control is declared as a datafield.  While doing so isn't important in this example, it will be necessary in all future ones.  We will declare all controls as datafields to the class in order to make them accessible to the handle method.

 

FULL CODE

 

Below is the full code excluding the import statements.  The code with the new concepts is highlighted in yellow.

 

public class FirstApplication extends Application implements EventHandler<ActionEvent>

{

     public Button b1;

    

     @Override

     public void start(Stage primaryStage) throws Exception

     {

          //CREATE CONTROLS

          b1 = new Button();

          b1.setText("Say Hi");

          b1.setOnAction(this);  //specify handler object

         

          //CREATE LAYOUT & ADD CONTROLS

          FlowPane layout = new FlowPane();

          layout.getChildren().add(b1);

         

          //CREATE SCENE AND ADD IT TO STAGE

          Scene s = new Scene(layout, 200, 100);

          primaryStage.setScene(s);

         

          //CONFIGURE & SHOW STAGE

          primaryStage.setTitle("Console Hello");

          primaryStage.show();

     }

 

     public static void main(String[] args)

     {

          Application.launch(args);

     }

 

     @Override

     public void handle(ActionEvent e)

     {

        System.out.println("Hello there.");

     }

}

 

 

 

PLACING OUTPUT IN A TEXTFIELD

 

When we create a GUI application, we don't actually want to use the console anymore.  We want to output to be placed inside the window itself.  One option is to place it inside a textfield object.

 

 

EXAMPLE 2 –  OUTPUT TO TEXTFIELD

 

The following window has a button that generates a random number and places it into the textfield.

 

 

NEW CODE EXPLANATION – CREATING TEXTFIELD

 

This program is quite similar to the previous one.  We have a TextField control that is a datafield.  It is constructed and added to the layout inside the start method. 

 

NEW CODE EXPLANATION – RESPONDING TO TEXTFIELD

 

In the handle method, we generate a random number and place that number in the textfield using the setText method.

 

FULL CODE

 

Below is the full code excluding the import statements.  The code with the new concepts is highlighted in yellow.

 

public class FirstApplication extends Application implements EventHandler<ActionEvent>

{

     public Button b1;

     public TextField t1;

    

     @Override

     public void start(Stage primaryStage) throws Exception

     {

          //CREATE CONTROLS

          b1 = new Button();

          b1.setText("Generate Number");

          b1.setOnAction(this);  //specify handler object

         

          t1 = new TextField();

         

          //CREATE LAYOUT & ADD CONTROLS

          FlowPane layout = new FlowPane();

          layout.getChildren().add(b1);

          layout.getChildren().add(t1);

         

          //CREATE SCENE AND ADD IT TO STAGE

          Scene s = new Scene(layout, 250, 70);

          primaryStage.setScene(s);

         

          //CONFIGURE & SHOW STAGE

          primaryStage.setTitle("TextField Number");

          primaryStage.show();

     }

 

     public static void main(String[] args)

     {

          Application.launch(args);

     }

 

     @Override

     public void handle(ActionEvent e)

     {

          String msg = ""+Math.random();

          t1.setText(msg);

     }

}

 

 

 

SOURCE OF EVENT

 

Most applications have more than one control that can create events.  We can tell which control triggered the event by making use of the ActionEvent object passed to the handle method.

 

 

EXAMPLE 3 – TWO BUTTONS

 

The window application below has two buttons that generate an event.  We see how to respond to each but differently.

 

 

NEW CODE EXPLANATION

 

We add a button to the window.  We also add a listener to the button. 

 

In the handle event, we differentiate between an event triggered by button #1 and #2 and place a corresponding message in the text field.

 

     public void handle(ActionEvent e)

     {

          if (e.getSource() == b1)

          {

              t1.setText("Hi there!");

          }

          else if (e.getSource() == b2)

          {

              t1.setText("Hey there!");

          }

     }

 

FULL CODE

 

Below is the full code excluding the import statements.  The code with the new concepts is highlighted in yellow.

 

public class FirstApplication extends Application implements EventHandler<ActionEvent>

{

     public Button b1;

     public Button b2;

     public TextField t1;

    

     @Override

     public void start(Stage primaryStage) throws Exception

     {

          //CREATE CONTROLS

          b1 = new Button();

          b1.setText("Hi");

          b1.setOnAction(this);

         

          b2 = new Button();

          b2.setText("Hey");

          b2.setOnAction(this);

         

          t1 = new TextField();

         

          //CREATE LAYOUT & ADD CONTROLS

          FlowPane layout = new FlowPane();

          layout.getChildren().add(b1);

          layout.getChildren().add(t1);

          layout.getChildren().add(b2);

         

          //CREATE SCENE AND ADD IT TO STAGE

          Scene s = new Scene(layout, 250, 70);

          primaryStage.setScene(s);

         

        //CONFIGURE & SHOW STAGE

          primaryStage.setTitle("Two Buttons");

          primaryStage.show();

     }

 

     public static void main(String[] args)

     {

          Application.launch(args);

     }

 

     @Override

     public void handle(ActionEvent e)

     {

          if (e.getSource() == b1)

          {

              t1.setText("Hi there!");

          }

          else if (e.getSource() == b2)

          {

              t1.setText("Hey there!");

          }

     }

}