Lecture 10 - California State University, Los Angeles

Download Report

Transcript Lecture 10 - California State University, Los Angeles

Lecture 10
CS202 Fall 2013
Preview of Generics
• Recall that a list is a list of objects of some type. We
show that using syntax like this:
List<Student> students;
• List is a generic data structure, meaning that we can
have lists of many different types of objects. It is
parameterized by the data type that the list will hold.
• Interfaces may be parameterized in the same way.
For example, when we declared that Student
implemented Comparable, the interface was
parameterized by the same class Student. This
means that the compareTo() method compares the
current Student to another Student.
Preview of Generics
• Lab 6 uses a parameterized interface called MyMath.
The Methods of MyMath implement binary
operations on classes that implement the interface.
• Binary operations are operations that involve two
instances of a data type
– Arithmetic addition is a binary operation involving
two real numbers (eg, 1.2 + 2.1)
– In Lab 6, you will write methods that perform
operations on two fractions or two sets of
integers.
Preview of Generics
• MyMath is parameterized by a data type. This is shown in the
interface code using T as a placeholder for the type.
• Your classes that implement MyMath will be parameterized
by the names of the same classes, ie
MyFraction implements MyMath<MyFraction>
• This means that the binary operations required by MyMath
and implemented in MyFraction are performed between the
current object and an object of type MyFraction (another
MyFraction or the same one).
– For example MyFraction.add(MyFraction o) adds this MyFraction to
another MyFraction and returns a reference to the resulting
MyFraction.
GUIs
• Other than JOptionPane methods, everything we have done so far
has involved command-line input and output.
• Practically all consumer-oriented software today uses Graphical
User Interfaces (GUIs, pronounced "gooeys")
• An attractive and easy to use UI makes a bigger impression on the
typical consumer than elegant program logic or even performance
does.
– Consumers buy sizzle, not steak.
– Bill Gates is the richest person in the world, but Richard Stallman can’t afford
a razor
• Java is heavily used in several types of GUI-based applications
– Web apps
– Android apps
– BluRay interface
GUIs
• When you started taking CS classes, you probably
expected to use GUI interfaces right away. There are
several reasons we don’t do it that way
– Traditions in the field; most instructors and textbook authors
started programming before GUIs were popular
– To the CS way of thinking, there is no point in having a great
GUI if you don’t know how to program any functionality
– GUI design shades into graphic arts and psychology rather
than strictly CS and requires different skills
– Finally, modern GUI construction uses OOP principles heavily,
so you have to learn those first
GUIs
• GUIs are usually built using frameworks or toolkits that provide
customizable GUI components.
• You do not have to write the code to define what a dialog box or a
radio button looks like. You will call methods of GUI classes that
have already done this and send the arguments that define the
specifics you want.
• GUIs are introduced in Java using the Java FX library. JavaFX code
is platform-independent, but your GUIs may look a little different
from platform to platform.
• The basic principles of JavaFX are very similar in most other types
of GUI programming you will encounter.
• When you learn server-side web programming in CS320, or
Android programming, you will build on this material.
JavaFX
• JavaFX is designed for networked applications.
• Until recently, Java GUI construction was usually taught using
Swing, a toolkit for desktop GUI apps. Java does not have much
market share in the desktop app market, so Swing has become
outmoded.
JavaFX
If you use Eclipse with JavaFX on the computers in A-220, include a main() like this
one:
public static void main(String[] args){
Application.launch(args);
}
On your own computer, you can install the Eclipse add-on e(fx)clipse. With this,
main() is unnecessary for JavaFX. You will also not need main() to compile and run
from a command line in current versions of Java.
In the lab, you may also need to set the build path to use an “alternate JRE.” Right
click on the project, then choose build path/ configure build path / libraries.
Highlight the JRE System Library, click Edit, then choose “alternate JRE.” Choose a
JRE8 (or later) JRE. This is just a bug in Eclipse.
JavaFX
• On your own computer, install e(fx)clipse, a plug in for Eclipse, if
necessary. If you do not see the “JavaFX application” option
when creating a project or if you get an error message in the line
of code that includes “extends Application”, this is probably the
problem.
• I needed to add e(fx)clipse with Eclipse Luna in Windows 8.1, but
the Eclipse Kepler package for Fedora Linux 20 included it already.
Your results may vary.
• Here is how to add a plug-in to Eclipse in Windows. If these
instructions don’t work in your OS, look for instructions on Stack
Overflow. If that doesn’t work, ask me in the lab or come to my
office hours.
–
–
–
–
Help/Find New Software
Enter search text (“JavaFX”)
Find the software you want
If an “install” button is present, click it. This should work for e(fx)clipse.
• Otherwise, follow a link from the search results for download and install instructions
JavaFX
start(Stage primaryStage) is the starting point of a JavaFX
application.
• Your start() overrides one from javafx.application.Application
• primaryStage is created automatically
Even with e(fx)clipse, Eclipse does not always see start() correctly as
a starting point. You may have to type the name of the package and
class in Run Configurations:
JavaFX
• There are many types of UI components, which are implemented
as classes in the JavaFX API. I will describe a few of them, but
mostly just use them when necessary.
• From this point on, we will be using too many API classes to
explain them all in advance. You will soon learn how to figure out
how to use classes you see in examples, based on conventions
and documentation; this is a key skill in OOP.
JavaFX
• The window in which JavaFX GUI components are placed is an
object of class Stage. JavaFX developers are afflicted with the Java
habit of giving things campy names. Don’t say I didn’t warn you.
• Stage has many setter methods like setTitle() and setWidth().
Experiment with these as you work.
• Individual UI components, like Labels and Buttons, are called
controls
• You can set up multiple Stages and swap them in and out; we will
cover that later.
JavaFX
• Each Stage has a Scene which holds the controls
• You can put controls like buttons directly into the Scene, but most
Scenes hold objects of subclasses of Pane. These serve as
containers for the controls. The first Pane we will try out is the
StackPane. This is a container which stacks the components it
holds in back-to-front order.
• The constructor for Scene takes a parameter that is a reference to
the root of the scene graph, eg the Stack Pane.
• You can add UI controls directly to the StackPane but there are
other containers you can use to get more control over layout.
• Once you have the Scene constructed, use Stage.setScene() to
make the particular Stage use the Scene
• Stage.show() makes the Stage actually appear
JavaFX
JavaFX offers two different ways to code the UI
– Both controls and functionality coded in Java. This is the way we will
initially work
– XML description of the controls, with Java code to define how they work.
This is similar to the way most (not all) web and mobile programming
frameworks work. We will try this method a little later.
Hello World in JavaFX
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Hello extends Application{
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Text txt = new Text("Hello, World!");
StackPane root = new StackPane();
root.getChildren().add(txt);
Scene sc = new Scene(root, 300, 250);
primaryStage.setScene(sc);
primaryStage.show();
}
}
JavaFX
StackPane stacks components in “back to front” order according to when they are
added to the Pane. Run this and then reverse the order of the two
root.getChildren() lines and run it again:
public class Hello extends Application{
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Text txt = new Text("Hello, World!");
Button b = new Button("Click me!");
StackPane root = new StackPane();
root.getChildren().add(txt);
root.getChildren().add(b);
Scene sc = new Scene(root, 300, 250);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Note that Text has a transparent background, so you can see through it to the button
JavaFX
• You may see many alternatives when importing
JavaFX classes. Look at them carefully for the
right ones for JavaFx. In the example below,
java.awt.Button would not be correct.
JavaFX
Group is another type of Pane that renders its components using specified x and y
coordinates. Experiment with the values of the parameters in this code:
@Override
public void start(Stage primaryStage) {
Group g = new Group();
Rectangle r = new Rectangle();
r.setWidth(200);
r.setHeight(100);
r.setFill(Color.RED);
r.setX(50);
r.setY(50);
Circle c = new Circle();
c.setRadius(100);
c.setFill(Color.GREEN);
c.setCenterX(300);
c.setCenterY(300);
g.getChildren().add(r);
g.getChildren().add(c);
Scene sc = new Scene(g, 750, 750);
primaryStage.setScene(sc);
primaryStage.show();
}
JavaFX Architecture
• A JavaFX user interface is based on a scene graph, which is a tree, much like an
html document. To review, the CS conception of a tree looks like this:
•
•
•
•
Other than the root, each node has one parent
Each node may have one or more children
A node with no children is called a leaf
All nodes are said to be contained within the root
JavaFX Architecture
• In JavaFX, the root of the scene graph tree is the pane.
Styling
• Each node in the scene graph has an id, size, and a style class.
The style class is actually a list of Strings that are the names of
CSS classes.
• This capability is new and is very limited.
• The CSS properties are specific to JavaFX, but they are usually
named after standard css properties and prefixed with "fx-"
• Oracle’s documentation of the CSS properties is preliminary, but
I won’t make you do anything too obscure with these in this
class.
Styling
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
sc.getStylesheets().add("styles/style.css");
Label l = new Label("Hello");
l.getStyleClass().add("arthur");
l.getStyleClass().add("beatrice");
s.getChildren().add(l);
primaryStage.setScene(sc);
primaryStage.show();
}
Styling
.arthur{
-fx-background-color: #FFFF00;
-fx-text-fill: #00DDFF;
}
.beatrice{
-fx-font-size: 500%;
}
Contents of style.css
Styling
• This setup separates the presentation from the content, which
makes it much easier to change them separately.
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
sc.getStylesheets().add("styles/style.css");
Label l = new Label("Hello");
boolean am = getAm();
if(am) l.getStyleClass().add("amstyle");
else l.getStyleClass().add("pmstyle");
s.getChildren().add(l);
primaryStage.setScene(sc);
primaryStage.show();
}
private boolean getAm(){
LocalDateTime d = LocalDateTime.now();
if(d.getHour() < 12) return true;
else return false;
}
}
Styling
.amstyle{
-fx-background-color: #FFFF00;
-fx-text-fill: #00DDFF;
-fx-font-size: 300%;
}
.pmstyle{
-fx-background-color: #FF00FF;
-fx-text-fill: #00FF00;
-fx-font-size: 400%;
}
Events
• Our programs so far have asked for input at times directed by
the code, then handled the input when given. Typically, a main
loop controls the timing of requests for input.
• GUI programs must handle events that are user-directed and
may occur at any time.
• GUI actions, such as button clicks, raise Events. In OOP, an event
is implemented as an object of some class. In JavaFX, these are
instances of subclasses of the EventObject class.
Event Handlers
• Event handlers specify which events the program will respond to
and what to do when they occur
• In JavaFX, these implement the EventHandler interface and are
parameterized by subclasses of Event, such as ActionEvent.
• You can add EventHandlers to may different types of GUI
components
• EventHandlers must implement the method handle(Event event)
• You can create an Event Handler object in many different ways
–
–
–
–
Code a class in a separate file and instantiate an object
Code an inner class and instantiate an object
Code an anonymous class and instantiate an object separately
Code an anonymous class and instantiate a one-of-a-kind object all at
once
Separate EventHandler Class
import javax.swing.JOptionPane;
import javafx.event.Event;
import javafx.event.EventHandler;
public class MyClickHandler<ActionEvent> implements
EventHandler<Event>{
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
Separate EventHandler Class
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
EventHandler<Event> handler = new MyClickHandler<Event>();
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Inner EventHandler Class
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
EventHandler<Event> handler = new MyClickHandler<Event>();
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
private class MyClickHandler<ActionEvent> implements EventHandler<Event>{
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
}
Anonymous EventHandler Class with Variable
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
// “anonymous” because we never name the class
EventHandler<Event> handler = new EventHandler<Event>(){
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
};
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Anonymous Class with Anonymous Object
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
b.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
});
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Anonymous Class with Anonymous Object
Open parenthesis begins parameter list for addEventhandler()
Beginning of method call
Call to EventHandler constructor
b.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
Open curly brace begins definition
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
Close curly brace ends definition of anonymous class
);
Semicolon ends addEventhandler() statement
of anonymous class
Close parenthesis ends parameter list for addEventhandler()
This idiom may be hard to get used to, but it is very common in many different
GUI programming frameworks, and will certainly be on the final exam.
ClickCounter
This application uses GUI components and EventHandlers in a slightly
more complex way:
• Place a grid of buttons on a GridPane
• Place a Label into in an Hbox (one-row Pane) indicating how many
buttons are currently clicked
• Attach EventHandlers to each button that track whether the
button is currently clicked or not clicked and update the
count displayed on the Label
• Add both Panes to a BorderPane
• Notice the use of String.valueOf() to convert numeric values to Strings
for display in labels
Click Counter
public class ClickCounter extends Application {
private int numClicked;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
bp.getStyleClass().add("grid");
GridPane gp = new GridPane();
Label clickedLabel = new Label("Buttons Clicked: ");
clickedLabel.getStyleClass().add("clickedLabel");
Label numClickedLabel = new Label("0");
numClickedLabel.getStyleClass().add("clickedLabel");
HBox clickedCounterBox = new HBox();
clickedCounterBox.getStyleClass().add("clickedBox");
clickedCounterBox.getChildren().add(clickedLabel);
clickedCounterBox.getChildren().add(numClickedLabel);
Scene sc = new Scene(bp);
sc.getStylesheets().add("styles/style.css");
numClicked = 0;
for (int rowCounter = 0; rowCounter < 10; rowCounter++)
for (int colCounter = 0; colCounter < 10; colCounter++) {
}
Click Counter
Button b = new Button("Unclicked");
b.setMinWidth(150);
b.getStyleClass().add("button");
b.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<Event>() {
Boolean clicked = false;
@Override
public void handle(Event event) {
if (clicked == true) {
clicked = false;
b.setText("Unclicked");
numClicked--;
} else {
clicked = true;
b.setText("Clicked");
numClicked++;
}
numClickedLabel.setText(String.valueOf(numClicked));
}
});
gp.add(b, colCounter, rowCounter);
}
bp.setTop(clickedCounterBox);
bp.setBottom(gp);
primaryStage.setScene(sc);
primaryStage.show();
}
}
CSS
.pane{
-fx-font-size: 250%;
-fx-padding: 20px;
}
.grid{
-fx-font-size: 200%;
}
.clickedLabel{
-fx-background-color: #00FFFF;
}
.clickedBox{
-fx-alignment: center;
}
Event Handling with Setters
JavaFX can also handle events using setter methods from the various
Node classes, like this:
Label l = new Label("Click Me!");
l.setOnMouseClicked(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
});
Event Handling with Lambda Expressions
• Simple event handling works well with lambda expressions, a
feature that is commonly used in functional programming and has
recently been introduced to Java.
• A Lambda expression is equivalent to an anonymous method
(Liang says an anonymous class)
• Here is a sample; e is the parameter name for the event, which is
passed into the lambda expression.. Later we will get information
from the event objects.
Label l = new Label("Click Me!");
l.setOnMouseClicked(e -> {
JOptionPane.showMessageDialog(null, "Thanks!");
}
);
Tuning GUI Appearance
There are at least two good ways to find details on how to adjust the
appearance of JavaFX GUIs:
• Google a phrase like "JavaFX background color" and see what you
find. Oracle documentation has the most info, but
StackOverflow.com usually has the most practical answers
• Use Eclipse's context-sensitive help: