CH 13 JavaFX
CH 13 JavaFX
Introduction to JavaFX
GUI Programming
Creation of GUI
Event driven programming
JavaFX Packages
• The JavaFX elements are contained in packages that
begin with the javafx prefix.
• Examples: javafx.application, javafx.stage, javafx.scene,
and javafx.scene.layout.
• Beginning with JDK 9, the JavaFX packages are organized
into modules, such as javafx.base, javafx.graphics, and
javafx.controls.
JavaFX Basic Concepts..
The Stage and Scene Classes
A stage is a container for scenes and a scene is a container for the items that comprise the
scene. These elements are encapsulated in the JavaFX API by the Stage and Scene classes.
To create a JavaFX application, you will, at minimum, add at least one Scene object to a
Stage.
Stage is a top-level container. All JavaFX applications automatically have access to one
Stage, called the primary stage.
The primary stage is supplied by the run-time system when a JavaFX application is started.
Although you can create other stages, for many applications, the primary stage will be the
only one required.
As mentioned, Scene is a container for the items that comprise the scene. These can consist
of controls, such as push buttons and check boxes, text, and graphics. To create a scene,
you will add those elements to an instance of Scene.
JavaFX Basic Concepts..
Nodes and Scene Graphs
The individual elements of a scene are called nodes. For example, a push
button control is a node.
However, nodes can also consist of groups of nodes. Furthermore, a node can
have a child node. In this case, a node with a child is called a parent node or
branch node. Nodes without children are terminal nodes and are called
leaves.
The collection of all nodes in a scene creates what is referred to as a scene
graph, which comprises a tree.
There is one special type of node in the scene graph, called the root node.
This is the top-level node and is the only node in the scene graph that does
not have a parent. Thus, with the exception of the root node, all other nodes
have parents, and all nodes either directly or indirectly descend from the root
node.
The base class for all nodes is Node. There are several other classes that are,
either directly or indirectly, subclasses of Node. These include Parent, Group,
Region, and Control, to name a few.
JavaFX Basic Concepts..
Layouts
• JavaFX provides several layout panes that
manage the process of placing elements in a
scene.
• For example, the FlowPane class provides a
flow layout and the GridPane class supports a
row/column grid-based layout.
• Several other layouts, such as BorderPane
are available. The layout panes are packaged
in javafx.scene.layout.
JavaFX Basic Concepts..
The Application Class and the Life-Cycle Methods
A JavaFX application must be a subclass of the Application class, which is
packaged in javafx.application. Thus, your application class will extend
Application.
The Application class defines three life-cycle methods that your application can
override. These are called init( ), start( ), and stop( ), and are shown
here, in the order in which they are called:
void init( )
abstract void start(Stage primaryStage)
void stop( )
The init( ) method is called when the application begins execution. It is used to
perform various initializations. As will be explained, however, it cannot be used
to create a stage or build a scene. If no initializations are required, this method
need not be overridden because an empty, default version is provided.
JavaFX Basic Concepts..
The Application Class and the Life-Cycle Methods..
The start( ) method is called after init( ). This is where your application
begins and it can be used to construct and set the scene. Notice that it
is passed a reference to a Stage object. This is the stage provided by the
run-time system and is the primary stage. (You can also create other
stages, but you won’t need to for simple applications.) Notice that this
method is abstract. Thus, it must be overridden by your application.
One other point: For a modular JavaFX application, the package that
contains your main application class (that is, your subclass of
Application) must be exported by its module so that it can be found by
the javafx.graphics module.
JavaFX Basic Concepts..
Launching a JavaFX Application
To start a free-standing JavaFX application, you must call the launch( ) method
defined by Application. It has two forms. Here is the one used in this chapter:
public static void launch(String … args)
Here, args is a possibly empty list of strings that typically specify command-line
arguments. When called, launch( ) causes the application to be constructed,
followed by calls to init( ) and start( ). The launch( ) method will not return until
after the application has terminated. This version of launch( ) starts the subclass
of Application from which launch( ) is called. The second form of launch( ) lets
you specify a class other than the enclosing class to start.
• import javafx.application.*;
• import javafx.scene.Scene;
• import javafx.scene.control.Button;
• import javafx.scene.layout.HBox;
• import javafx.stage.Stage;
• }
• @Override
• public void start(Stage PrimaryStage) throws Exception {
• //label Output
• Button btn=new Button("Click Me");
•
• //Layout
• HBox root=new HBox();
•
• root.getChildren().add(btn);
•
• // Scene
• Scene scene=new Scene(root,500,200);
•
• //Stage
• PrimaryStage.setScene(scene);
• PrimaryStage.setTitle("My First Example");
• PrimaryStage.show();
• }
• }
The Application Thread
The init( ) method cannot be used to construct a stage or scene. You
also cannot create these items inside the application’s constructor. The
reason is that a stage or scene must be constructed on the application
thread.
However, the application’s constructor and the init( ) method are
called on the main thread, also called the launcher thread. Thus, they
can’t be used to construct a stage or scene.
Instead, you must use the start( ) method, as the skeleton
demonstrates, to create the initial GUI because start( ) is called on the
application thread.
Furthermore, any changes to the GUI currently displayed must be
made from the application thread. Fortunately, in JavaFX, events are
sent to your program on the application thread. Therefore, event
handlers can be used to interact with the GUI.
The stop( ) method is also called on the application thread.
A Simple JavaFX Control: Label
The primary ingredient in most user interfaces is the control because a
control enables the user to interact with the application. As you would
expect, JavaFX supplies a rich assortment of controls.
The simplest control is the label because it just displays a message, which, in
this example, is text. Although quite easy to use, the label is a good way to
introduce the techniques needed to begin building a scene graph.
The Labeled class defines several features that are common to all labeled
elements (that is, those that can contain text), and Control defines features
related to all controls.
A Simple JavaFX Control: Label
Label defines three constructors.
• Label(): Creates an empty label
• Label(String text): Creates Label with given text.
• Label(String text, Node g): Creates a Label with the given text and graphic.
Once you have created a label (or any other control), it must be added to the
scene’s content, which means adding it to the scene graph. To do this, you will first call
getChildren( ) on the root node of the scene graph. It returns a list of the child nodes in the
form of an ObservableList<Node>.
As you know, most GUI controls generate events that are handled by your
program. For example, buttons, check boxes, and lists all generate events
when they are used.
One commonly used control is the button. This makes button events one of
the most frequently handled. Therefore, a button is a good way to
demonstrate the fundamentals of event handling in JavaFX. For this reason,
the fundamentals of event handling and the button are introduced together.
Using Buttons and Events..
Event Basics
The base class for JavaFX events is the Event class, which is packaged in javafx.event.
Event inherits java.util.EventObject, which means that JavaFX events share the same
basic functionality as other Java events.
Several subclasses of Event are defined. The one that we will use here is ActionEvent.
It handles action events generated by a button.
In general, JavaFX uses what is, in essence, the delegation event model approach to
event handling. To handle an event, you must first register the handler that acts as a
listener for the event. When the event occurs, the listener is called. It must then
respond to the event and return.
Events are handled by implementing the EventHandler interface, which is also in
javafx.event. It is a generic interface with the following form:
The following program demonstrates check boxes. It displays four check boxes that
represent different types of computers. They are labeled Smartphone, Tablet, Notebook,
and Desktop. Each time a check-box state changes, an action event is generated. It is
handled by displaying the new state (selected or cleared) and by displaying a list of all
selected boxes.
// Demonstrate Check Boxes.
import javafx.application.*;
import javafx.scene.*;
import javafx.stage.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.event.*;
import javafx.geometry.*;
public class CheckboxDemo extends Application {
CheckBox cbSmartphone;
CheckBox cbTablet;
CheckBox cbNotebook;
CheckBox cbDesktop;
Label response;
Label selected;
String computers;
public static void main(String[] args) {
// Start the JavaFX application by calling launch().
launch(args);
}
// Override the start() method.
public void start(Stage myStage) {
// Give the stage a title.
myStage.setTitle("Demonstrate Check Boxes");
// Use a vertical FlowPane for the root node. In this case,
// vertical and horizontal gaps of 10.
FlowPane rootNode = new FlowPane(Orientation.VERTICAL, 10, 10);
// Center the controls in the scene.
rootNode.setAlignment(Pos.CENTER);
// Create a scene.
Scene myScene = new Scene(rootNode, 230, 200);
// Set the scene on the stage.
myStage.setScene(myScene);
Label heading = new Label("What Computers Do You Own?");
// Create a label that will report the state change of a check box.
response = new Label("");
// Create a label that will report all selected check boxes.
selected = new Label("");
// Create the check boxes.
cbSmartphone = new CheckBox("Smartphone");
cbTablet = new CheckBox("Tablet");
cbNotebook = new CheckBox("Notebook");
cbDesktop = new CheckBox("Desktop");
// Handle action events for the check boxes.
cbSmartphone.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent ae) {
if(cbSmartphone.isSelected())
response.setText("Smartphone was just selected.");
else
response.setText("Smartphone was just cleared.");
showAll();
} });
cbTablet.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent ae) {
if(cbTablet.isSelected())
response.setText("Tablet was just selected.");
else
response.setText("Tablet was just cleared.");
showAll();
}
});
cbNotebook.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent ae) {
if(cbNotebook.isSelected())
response.setText("Notebook was just selected.");
else
response.setText("Notebook was just cleared.");
showAll();
}
});
cbDesktop.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent ae) {
if(cbDesktop.isSelected())
response.setText("Desktop was just selected.");
else
response.setText("Desktop was just cleared.");
showAll();
}
});
// Add controls to the scene graph.
rootNode.getChildren().addAll(heading, cbSmartphone, cbTablet,
cbNotebook, cbDesktop, response, selected);
// Show the stage and its scene.
myStage.show();
showAll();
}
// Update and show the selections.
void showAll() {
computers = "";
if(cbSmartphone.isSelected())
computers = "Smartphone ";
if(cbTablet.isSelected())
computers += "Tablet ";
if(cbNotebook.isSelected())
computers += "Notebook ";
if(cbDesktop.isSelected())
computers += "Desktop";
selected.setText("Computers selected: " + computers);
}
}
Sample output is shown here:
ListView
A ListView can display a list of entries from which you can select one or more. Scrollbars
are automatically added when the number of items in the list exceeds the number that can
be displayed within the control’s dimensions. ListView is a generic class that is declared
like this:
class ListView<T>
Here, T specifies the type of entries stored in the list view. Often, these are entries of type
String, but other types are also allowed.
Here is the ListView constructor that we will use:
ListView(ObservableList<T> list)
The list of items to be displayed is specified by list. It is an object of type ObservableList.
ObservableList supports a list of objects.
By default, a ListView allows only one item in the list to be selected at any one time. You
can allow multiple selections by changing the selection mode, but we will use the default,
single-selection mode.
To create an ObservableList for use in a ListView is to use the factory method
observableArrayList( ), which is a static method defined by the FXCollections class (which
is packaged in javafx.collections).
static <E> ObservableList<E> observableArrayList(E ... elements)
In this case, E specifies the type of elements, which are passed via elements.
to set the preferred height and/or width, size:
final void setPrefHeight(double height)
final void setPrefWidth(double width)
void setPrefSize(double width, double height)
you can monitor the list for changes by registering a change listener. This lets you
respond each time the user changes a selection in the list. A change listener is supported
by the ChangeListener interface, which is packaged in javafx.beans.value. The
ChangeListener interface defines only one method, called changed( ). It is shown here:
void changed(ObservableValue<? extends T> changed, T oldVal, T newVal)
In this case, changed is the instance of ObservableValue<T> which encapsulates an object
that can be watched for changes. The oldVal and newVal parameters pass the previous
value and the new value, respectively. Thus, in this case, newVal holds a reference to the
list item that has just been selected.
To listen for change events, you must first obtain the selection model used by the
ListView. This is done by calling getSelectionModel( ) on the list. It is shown here:
final MultipleSelectionModel<T> getSelectionModel( )
It returns a reference to the model.
Using the model returned by getSelectionModel( ), you will obtain a reference to the
selected item property that defines what takes place when an element in the list is
selected.
This is done by calling selectedItemProperty( ), shown next:
final ReadOnlyObjectProperty<T> selectedItemProperty( )
You will add the change listener to this property by using the addListener( ) method on
the returned property. The addListener( ) method is shown here:
void addListener(ChangeListener<? super T> listener)
In this case, T specifies the type of the property.
The following example creates a list view that displays a list of computer types, allowing
the user to select one. When one is chosen, the selection is displayed.
// Demonstrate a list view.
import javafx.application.*;
import javafx.scene.*;
import javafx.stage.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.geometry.*;
import javafx.beans.value.*;
import javafx.collections.*;
public class ListViewDemo extends Application {
Label response;
public static void main(String[] args) {
// Start the JavaFX application by calling launch().
launch(args);
}
// Override the start() method.
public void start(Stage myStage) {
// Give the stage a title.
myStage.setTitle("ListView Demo");
// Use a FlowPane for the root node. In this case,
// vertical and horizontal gaps of 10.
FlowPane rootNode = new FlowPane(10, 10);
// Center the controls in the scene.
rootNode.setAlignment(Pos.CENTER);
// Create a scene.
Scene myScene = new Scene(rootNode, 200, 120);
// Set the scene on the stage.
myStage.setScene(myScene);
// Create a label.
response = new Label("Select Computer Type");
// Create an ObservableList of entries for the list view.
ObservableList<String> computerTypes =
FXCollections.observableArrayList("Smartphone", "Tablet", "Notebook", "Desktop" );
// Create the list view.
ListView<String> lvComputers = new ListView<String>(computerTypes);
// Set the preferred height and width.
lvComputers.setPrefSize(100, 70);
// Get the list view selection model.
MultipleSelectionModel<String> lvSelModel = lvComputers.getSelectionModel();
// Use a change listener to respond to a change of selection within a list view.
lvSelModel.selectedItemProperty().addListener( new ChangeListener<String>() {
public void changed(ObservableValue<? extends String> changed,
String oldVal,
String newVal) {
// Display the selection.
response.setText("Computer selected is " + newVal);
}
});
// Add the label and list view to the scene graph.
rootNode.getChildren().addAll(lvComputers, response);
// Show the stage and its scene.
myStage.show();
}
}
Sample output is shown here.
Notice that a vertical scroll bar has been included so that the list can be scrolled
to see all of its entries.
JavaFX ComboBox
ComboBox