Java Preliminaries
Do
not be misled by the title, this doc contains both elementary and intermediate
Java material.
TOC:
·
Java Preliminaries: classes, interfaces
·
Interfaces in Java
I
have provided some preliminary topics and there will be many java examples
throughout the semester. Students
unfamiliar with the Java API need to make an effort to get as many of the
examples working as possible
There
are many kinds of entities in Java. Usually we will create objects (which are
defined as classes in Java or C++).
·
We may want to test them in an application.
In java, an application is just a class with a special main function, as it is
in C++, and it runs locally, on the desktop.
However, an application can have an elaborate UI. Additionally, an application can open sockets and communicate across the
internet.
·
We may choose to create applets or servlets
instead. These classes extend
particular super classes. Applets are client-side internet
programs and can run in a browser window. (The file appletviewer.exe will also
run your applet in the blackscreen.) They are safe to
run because they are unable to manipulate files on your disk drives. The applet bytecode
is streamed to the browser which runs it.
Threads allow for multiple
lines of execution – often necessary for graphics and games, among other
things. An example below shows a thread
in an applet.
·
A servlet
is server-side code and must be run in a servlet container, a sort of
mini-server, like Glassfish, Tomcat, Jetty, or JBoss. We will develop servlets, too, since servlets
are at the heart of web-apps.
·
Groovlets are
bits of Groovy code, or entire classes, which can be deployed as a webapp in a container. We may develop Groovlets.
·
Portlets are
pluggable user interface software components that are managed and displayed in
a web
portal. Portlets produce fragments of markup code
that are aggregated into a portal page. Typically, following the desktop
metaphor, a portal page is displayed as a collection of non-overlapping portlet windows, where each portlet
window displays a portlet. Hence a portlet (or collection of portlets)
resembles a web-based application that is hosted in a portal. Some examples of portlet
applications are email,
weather
reports, discussion forums, and news. Depending on time constraints, we may have a portlet and or GWT project.
1.
Objects: A sub class object derives from a super class object in java by extending that concrete or abstract
object. An object in Java can extend at most one super class. Java was designed this way to sidestep some
of the thorny maintenance issues of C++ software. This is written
class X extends Y{…}
2.
Interfaces: In Java, an interface is a collection of methods having no bodies, what is
called virtual in C++. An
interface may only define static or final data fields. An interface is an ADT, like a stack or tree or hashtable,
for example. It is a bunch of methods we
would like anything of the given type to be able to perform. An object implements an interface by defining
each method of the interface. An object that does not implement all methods of
an interface can’t be instantiated and must be declared abstract. Abstract objects
can be extended. An object in Java may
implement as many interfaces as it likes.
In this way we are not hindered by the subclass restrictions in Java. This is written
class X implements Y{…}
As
you've already learned, objects define their interaction with the outside world
through the methods that they expose. Methods form the object's interface
with the outside world; the buttons on the front of your television set, for
example, are the interface between you and the electrical wiring on the other
side of its plastic casing. You press the "power" button to turn the
television on and off.
In its most common
form, an interface is a group of related methods with empty bodies. A bicycle's
behavior, if specified as an interface, might appear as follows:
interface Bicycle {
void changeCadence(int newValue); // wheel
revolutions per minute
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
To
implement this interface, the name of your class would change (to a particular
brand of bicycle, for example, such as ACMEBicycle),
and you'd use the implements keyword in the class declaration:
class ACMEBicycle
implements Bicycle {
// remainder of this class implemented as
before
}
Implementing an interface allows a class to
become more formal about the behavior it promises to provide. Interfaces form a
contract between the class and the outside world, and this contract is enforced
at build time by the compiler. If your class claims to implement an interface,
all methods defined by that interface must appear in its source code before the
class will successfully compile.
3.
An
unfinished class or method is marked with the keyword abstract.
This corresponds to virtual in C++. It is a
way of preventing someone from instantiating a class that is supposed to be
extended first. An abstract class is deliberately
missing some or all of the method bodies. An abstract
method is deliberately missing its method body. An abstract
class is similar to an interface which is missing
all the method bodies. An abstract class provides a
base for someone to extend an actual class. You can’t use new
on abstract classes, but you can use abstract references, which always point to objects of a
class that extends the abstract class. Interfaces
are implicitly abstract as are all their methods.
To use make
practical use of an abstract class, you must define
a non-abstract class that extends the abstract
one. It can use any of the inherited non-abstract
methods. It must implement any of the abstract ones.
Sometimes an
abstract class may extend another abstract class. In that case it need not implement all the
non-abstract methods.
A
way to cut down on clutter is to avoid various trivial custom configuring
methods that your concrete classes must implement. Instead have the configuring
constructor pass the configuring data to the generic abstract constructor, much
the way a convenience constructor passes constants to an elaborate constructor
to fill in the defaults.
An
interface allows somebody to start from scratch to
implement your interface or to implement your interface in some other code whose original or primary
purpose was quite different from your interface. To
them, your interface is only incidental, something
that they must implement in their code to be able to use your package.
An
abstract class, in contrast, provides more
structure. It usually defines some default implementations and provides some
tools useful for a full implementation. The catch is, code using it must
use your class as the base. That may be highly inconvenient if the other
programmers wanting to use your package have already developed their own class
hierarchy independently. In Java, a class can inherit from only one base class.
You can offer the best of both worlds, an interface and an abstract
class. Implementors can ignore your abstract class if they choose. The only drawback of doing
that is calling methods via their interface name is
slightly slower than calling them via their abstract
class name.
Getting started. Aside.
You will need a current java sdk on your
machine. You can get it here: http://www.oracle.com/technetwork/java/javase/downloads/index.html Additionally, (see
below), you will need Ant and Maven. For all of these, you must configure path
and classpath settings. See installation instructions with each package.Java has the same control structures and many of
the same datatypes as C++. It is THE #1 development language. The SDK will have a bin directory. Java.exe and javac.exe (the interpreter and
compiler) are located in here. You
should fix path settings to access them from any directory. Appletviewer.exe is also in there, useful for
testing applets before deployment.
What would we like to do? Define some interesting (reusable!)
classes. Run them. JPanels and JFrames are important classes to learn to use. There are many important interfaces as well,
including ActionListener, ItemListener,
Runnable, Remote, WindowListener, MouseListener,
MouseMotionListener, and so on. Examples of some of these classes and
interfaces appear below. If you don’t
have it, you’ll need java itself. A Java
class named name.java must be
compiled using
javac name.java
This
creates a bytecode file called name.class. Obviously, java must be in the path settings.
java name
Will
run a java class named name. Some IDEs can compile and run java. Netbeans and
Eclipse are two popular IDEs. You should
download and install one of them. If you
get Eclipse, make sure to get the java version.
Java Eclipse is working in the labs.
It is in the labshare directory. Textpad is a handy
little IDE, useful if your project isn’t large. You can configure its preferences
to compile and run java or c programs.
1. Example.
A paint panel. We would like to put an
image on a panel or draw on it using the mouse.
A panel can be an image observer, which means it can
have an image on it. It can have a
graphics object associated with it. An
application or applet or whatever, that wants to display an image or allow for
drawing (as a canvas) would typically have a panel on it. A panel is itself a container and can have
other components on it as well. Here an
applet displays an image on “itself” – it can do this because an applet extends
panel. Of course, the jpg must be in
your directory.
Aside: applets running anywhere except in Textpad
as configured in campus labs will need an html to load into browser
window. Browser can run java, and the
html instructs browser where to get bytecode. Call this html file anything:
<html>
<applet code= "ShowImage.class" height=400 width=600>
</applet>
</html>
import javax.swing.*;
import java.awt.*;
public class ShowImage extends JApplet {
String
picture="indigobunting.jpg";//or the name of some other image file
Image image;
public void init(){
image=getImage(getCodeBase(),picture);
this.repaint();
}
public void
paint(Graphics g){
g.drawImage(image,0,0,this);
}
} //
end class
2.
This is a bit harder to do with a JFrame. JFrame is not an image observer, (although
you could make it implement this interface).
But a Panel (JPanel) is an image observer, and typically, you would like
to put something on your frame anyway (right?).
We can redo the above example with an application program which opens a
frame. The frame has an object on it
which extends JPanel. Here are the two
classes. (No screen shot provided).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class StillLife extends JFrame
{
public static PicturePanel center;
public static String name = "cat";
public static Image picture;
public StillLife() {
super();
Container c = getContentPane();
c.setLayout(new BorderLayout());//a layout with
a large center area
this.setBounds(100, 100, 400, 400);
Toolkit toolkit = Toolkit.getDefaultToolkit();
//need to get toolkit to build an image in this example because
JFrame is not image observer
picture = toolkit.createImage(name + ".gif");
center = new PicturePanel(picture);//give image to panel
to display
c.add(center, BorderLayout.CENTER);
setVisible(true);//else can’t see it
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//application
will terminate when window is closed
}
public static void main(String args[]) {
StillLife ss = new
StillLife();
System.out.println("main");
}
}
import javax.swing.*;
import java.awt.*;
public class PicturePanel extends JPanel
{
Image image;
public void update(Image x) {
image = x;
repaint();
}
public PicturePanel(Image x) {
image = x;
repaint();
}
public void paint(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
}
}
A mousepaint/thread sort of example is in
lesson2_Adapter.html
Preparation for writing code:
·
Your
environment. You’ll need an
up-to-date version of java, like jdk 1.7 Follow instructions, particularly in terms of setting
up class paths & paths. You will need to fix up your system paths and class
paths (look in control panelàsystemàadvancedà
environment variables to do this.) You
need java and maven to be found from any directory on your system. You can do
our course work in the Mathlab as well.
You may not be able to do it in a general purpose lab for various
reasons.
·
Your build
practices. As projects get more
complicated, you’ll want to use ant or maven, possibly in combination with an
IDE (Netbeans, Eclipse, or, minimally, a tool like Textpad)
Data encapsulation is a big
idea. It is where and why classes came
to be. Of course, since we’re
programming in Java, even though we haven’t gotten very far, we’ve already built
some classes. We looked at Scanner, a
pretty sophisticated class with powerful methods.
You know that the sort of
entities you have to deal with in your day-to-day programming are not simply int values (ages, say) or doubles (GPAs, e.g,) but rather are
made up of diverse data, some of it structured and complicated (like a list of
college courses or grades or an address) all associated with a single entity,
say a student.
Encapsulation means that a data
object should come with the methods needed to access (get), mutate (set), and
process the data in an application-specific way. Encapsulation also means that
clients should not automatically have access to data values. Java programmers use the words getters and setters to refer to the standard methods for getting a field value
or setting its value. The point (of
Java) was to move away from dangerous programming features like pointers,
multiple class inheritance, global variables:
Objects which can directly access or change one another’s variables
exhibit tight coupling. Tight coupling
means that changes to one class mean classes using it may need to be
modified. Just locating all those
classes might be hard. Figuring out how
to change them to adjust for changes in the original class might be very
hard. We restrict sharing information
about our class with client classes using access modifiers. Java supports
defaulted, public, protected and private access. Access modifiers like private, public and protected
indicate what classes may access a particular field or method. Failure to specify access is not an error,
but defaults to package access. Failure to specify a package is not an error,
but defaults to directory packaging. More on all these issues later.
Attributes and Methods: I
will use the word field to name an attribute or what in C++ is called a data member for a class. I will use method and function
interchangeably to identify a piece of code that can be referenced (called,
accessed, invoked) from elsewhere by name. In java, classes (objects) may have
fields and methods, but do not need to have either.
public class UselessClass{//contains no
fields or methods…rather useless
}
IDE Tip: A good IDE like
Eclipse will show you all the accessible fields and methods of any class when
you put a dot “.” next to the identifier name as you write your code. This saves some memorization and speeds up
your programming.
Java convention is that for a
class field named field, getField()
would name its getter and setField(..)
would name its setter. A good IDE like
Eclipse will paste in stubs for getters, setters and constructors when you
rt-click in the code window and select sourceàadd getters and setters or sourceàadd constructors.
Primitive types like int do not need to be instantiated
(created), only declared (and usually initialized). Objects generally must be
instantiated with the new
keyword. (There are occasional
exceptions. For example, a String can be
‘created’ with a simple assignment or using the new keyword. Image may not be created with new. Instead the container must create
an image for you. We’ll see examples of these.)
MyObject x=new MyObject();//This is a call to the default constructor
for MyObject.
Don’t worry, if you didn’t
provide a default constructor for your class, Java will, but it might not be
the code you wanted. The default
constructor takes no parameters and provides a mechanism for an outside client
with little knowledge of the class to instantiate it. Bean convention is to provide a default
constructor. Often, constructors take arguments corresponding to field values.
When creating methods (which
word I often use interchangeably with functions) Java allows passing parameters
only by value. The C++ mechanism
provided by notation &var in a
parameter list, for example, does not exist in Java. However, object parameter values are their
references, so objects passed to a method have effectively been passed by
reference. Arrays are also objects.
A reference to an object is an
identifier, perhaps passed into a method as a parameter or instantiated by a
framework like Spring.
SomeClass myRef=otherRef;//creates myRef
pointing at the object otherRef.
The fields and methods of otherRef
would be available using the usual conventions on myRef.
A real example that we build
ourselves: Note first, most classes are not applications (or applets, servlets
or portlets)! They are collections of data fields along with the methods needed
to manipulate them! Applications are themselves classes, which often manipulate
other classes.
public class Person{
String firstName;
String lastName;
String SS_num;
int age;
//ask Eclipse to add getters, setters and constructors… but here are a
few:
//what does public mean here? A client instantiating this class can use
the field or method
public int getAge(){return age;}//see the convention for getter setter
names?
public void setAge(int age){this.age=age;}//I just showed you another
java convention… what?
public String getFirstName(){return firstName;}
public
Person(){firstName=lastName=”unknown”;SS_num=”999-99-9999”;age=0;}
//default constructor
//…more code here
}
Here I had Eclipse add getters
and setters and constructors to this class:
3.
Example.
public class Person{
String firstName;
String lastName;
String SS_num;
int age;
//ask Eclipse to add getters, setters
and constructors… but here are a few:
//what does public mean here? A client
instantiating this class can use the field or method
public int getAge(){return age;}//see the
convention for getter setter names?
public void setAge(int age){this.age=age;}//I just
showed you another java convention… what?
public String
getFirstName(){return firstName;}
public Person(){firstName=lastName="unknown";SS_num="999-99-9999";age=0;}
public Person(String
firstName, String lastName, String sS_num, int age) {
super();
this.firstName = firstName;
this.lastName = lastName;
SS_num = sS_num;
this.age = age;
}
public String
getLastName() {
return lastName;
}
public void
setLastName(String lastName) {
this.lastName = lastName;
}
public String
getSS_num() {
return SS_num;
}
public void
setSS_num(String sS_num) {
SS_num = sS_num;
}
public void
setFirstName(String firstName) {
this.firstName = firstName;
}
}
It is convention in Java when
writing a constructor or setter to pass a param with the same identifier as the
field name it is to be assigned to. This
saves some head scratching later. The this keyword is used to disambiguate
the identifier in your code.
public void
setLastName(String lastName) {
this.lastName = lastName;
}
BTW: An array of objects must
be allocated as an array, and then each position/entry in the array must also
be allocated, both using the new keyword.
Person people[];//declared, yes, but currently a null pointer so don’t
reference it
people =new Person[100];//people is not null anymore but its
(subscripted) entries are
for(int x=0;x<100;x++){
people=new Person();//calling
default constructor 100 times
Note: If you get the common error Null pointer exception, it is
because you failed to allocate some object.
Add the class Person in Example
9 to a project and build a person array and populate it, using simple scanner
methods. Rt-click the project node (not
the file/application or src node) in the project explorer and add a file named
data.txt. Here is our data file. Observe
newlines:
Bob
Hope
111-11-1111
78
Bing
Crosby
222-22-2222
89
Michael
Jordan
333-33-3333
55
King
Kong
444-44-4444
43
Put the Person class in the examples package. Rt-click the package examples node in the project explorer
and add a file named PeopleApp. Some
features of this example. Remember I said I/O was trickier in Java than in
C+? Java does not handle exceptions for
you the way C++ did. A responsible
programmer handles her own exceptions. I create a FileReader for which try/catch clauses are required, because an
exception can be thrown. The exception
that can be thrown by creating the file reader around a String (file name) is a
FileNotFoundException. If this occurs, I
will print a message to the console- handy for debug purposes. But I can still wrap a Scanner around the
filereader and process my input using mostly familiar scanner methods. Here is our person processor app:
4. Example: Note package
and imports
package examples;
import
java.util.Scanner;
import java.io.*;
public class PeopleApp {
static Person people[];
final static int MAX = 100;
public static void main(String[]
args) {
try {
FileReader fr = new FileReader("data.txt");
Scanner scan = new Scanner(fr);
people = new Person[MAX];// must
allocate array reference to some
// max size
int num = getPeople(people, scan);
viewPeople(people, num);
} catch (FileNotFoundException
fnfe) {
System.out.println("file not
found");
}
}
private static int
getPeople(Person[] people,
Scanner scan) {
int ctr = 0;// got to
count, right?
while (scan.hasNext()
&& ctr < MAX) {// check for more also watch max
String
first = scan.next();
String last = scan.next();
String ss = scan.next();
int age =
scan.nextInt();
people[ctr] = new Person(first,
last, ss, age);/* build new person from constructor*/
ctr++;// we are one
ahead, right?
}
return ctr;// send back
count
}
private static void
viewPeople(Person[] people, int howMany) {
for (int j = 0; j <
howMany; j++)
System.out.println(people[j].getFirstName()
+ "
"
+
people[j].getLastName() + " " + people[j].getSS_num()
+ " " + people[j].getAge());
}
}
Here is output to console:
Bob Hope
111-11-1111 78
Bing Crosby
222-22-2222 89
Michael Jordan
333-33-3333 55
King Kong
444-44-4444 43
We are a bit dissatisfied
because there’s no fancy GUI to go with our app. Don’t worry. We’ll get there. We have just looked at an example of simple
array processing for a class.
C++ and Java support method
overload, which means a method (name) may be reused/coded in several ways with
various return types, but each version must have a different param list (called
its signature).
In C++ the operators (+, =, -,
*, >>, <<, and so on) are methods and can be overloaded. Not so in
Java.
As an example of overloading,
it is standard practice to provide multiple constructors for a class. The default constructor should always be
provided, and then various constructors from fields as appropriate. Consider a Person class. We coded getters and setters (which make no
sense to overload) and a default constructor.
Here is another constructor:
public Person(String firstName, String lastName, String SS_num, int
age)
{this.firstName=firstName;this.lastName=lastName;this.SS_numSS_num;this.age=age;}
// constructor from fields… an overloaded method
5. Example. Here is an application program which uses two
important classes, a JFrame and JPanel.
Both are common UI components.
Both are containers, which means other containers or widgets may be
placed on them. Our app StillLife is a JFrame: It extends (is a sub class
of) the class JFrame. The panel on the frame extends the JPanel class. J-Components are in the package javax.swing,
so we need an import. Image and Graphics
classes are in the java.awt package and if we wanted to add any listeners (like
a windowClosing event handler, or a listener for a JButton to change the
display) we would need java.awt.event package classes. They are not used here though.
BTW: class fields are normally
private access. Class methods are
normally public. Another class
instantiating this class can’t access the fields directly but can call the
methods. I don’t always remember to put private in front of these- but you
should. If you forget, and don’t
explicitly provide an access modifier, then access defaults to the
package/directory.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class StillLife extends JFrame
{//my class Is A JFrame
private static
PicturePanel center;//my class Has A PicturePanel which Is A JPanel
private static String name = "cat";
private static Image picture;
public StillLife() {
super();
Container c = getContentPane();
c.setLayout(new BorderLayout());//a layout with
a large center area
this.setBounds(100, 100, 400, 400);
Toolkit toolkit = Toolkit.getDefaultToolkit();
//need to get toolkit to build an image in this example because
JFrame is not image observer
picture = toolkit.createImage(name + ".gif");
center = new PicturePanel(picture);//give image to panel
to display
c.add(center, BorderLayout.CENTER);
setVisible(true);//else can’t see it
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//application
will terminate when window is closed
}
public static void main(String args[]) {
StillLife ss = new
StillLife();//must instantiate class with constructor.
System.out.println("main");
}
}
import javax.swing.*;
import java.awt.*;
public class PicturePanel extends JPanel
{
Image image;
public void update(Image x) {
image = x;
repaint();
}
public PicturePanel(Image x) {
image = x;
repaint();
}
public void paint(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
}
}
Was
that pretty complicated? It has no functionality but shows how classes might be
used together. If you extend another class (your super) and wish to have happen whatever happens in the constructor
for your super class, your constructor must call the super constructor as its
first line of code.
Before
building something more complicated, let’s build a simple UI to perform some
action. Let’s take a GPA example. What if we could enter course grades and
compute a GPA in a UI? We would want a
reset button in case we goofed in entering data or wanted to compute a
different student’s GPA. We need buttons
and the event handling for them.
Java
is an event-driven language. When events
are fired by listeners, we provide code to tell what should happen. Buttons in Java use the ActionListener
interface. Implementing an interface
makes a contract with the compiler that the application will provide the
methods of the interface. Your IDE will
usually prompt you if you have forgotten to do this, and it is a compile error:
XYZ
class must be declared abstract, it does not implement ABC method.
Java
provides many layout patterns for its containers. (A container is a component that can hold
other components, like a panel or frame.)
We can’t learn them here. We will
have to rely on very simple layouts for our projects. What do we want our GPA app to look
like? Let’s draw something.
We
need to learn some widgets. JLabels,
JButtons and JTextFields will do for this application. A textfield is a place where the user could potentially
enter data. A label or button is not
editable by the user, although its properties can be changed at run time by the
app. A button can have text or an image
on it. Using the ActionListener
interface, buttons and textfields can “listen” and we provide code for event
handling.
This
seems simple enough but even laying out these widgets might be
problematic. One simple layout in Java
is gridlayout. This works if you can
mostly arrange your widgets in rows of equal length. We might move the buttons above the GPA
display, and then we’d have 2 rows of 2 widgets each and 1 row of 1
widget. In grid and flow layout, widgets
are placed on the layout in the order in which they are added. For grid, this
is row-by-row. So some care must be
taken in adding the widgets in the correct order.
In
development we often work on parts of our application separately. First, let’s just see if we can build the UI.
Then we’ll add functionality.
Here’s
my Eclipse wizard: I am building a class that derives from JFrame and I want a
main method.
The
name of your app doesn’t matter too much. I called mine GPA_Application.
We
need to figure out the fields of our class.
Fields are the widgets and values (possibly objects) that need to be
accessed in more than one method. They
are declared right at the top of your class, typically. We need to think about imports. These are mostly determined in this example
by our UI. The J-components all arrived
with Java 1.2 and are in the javax.swing package. Here’s my class so far (package omitted).
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JLabel;
public class GPA_Application extends JFrame {
private int gradeCount;
private double currentSum;
private JButton addGrade,reset;
private JTextField gradeField;
private JLabel gradeLabel;
private JLabel gpaLabel;
public static void main(String[] args) {
}
}
Don’t
worry if you don’t know why I’ve got all those variables declared. Since widgets are objects, I need to build
them using an appropriate constructor and the new keyword. Primitives (our variables letter and gpa, for example)
may need to be initialized but are not allocated with new.
Frames
need to be closed properly, visibility set and sized or positioned, as we did
in our example 11 above. Allocating
widgets, setting layout, adding widgets to the layout, setting size, visibility
and frame position can all be done in the frame’s constructor. Here’s my constructor. Eclipse will show you a red circle with an x
in it for errors on some lines. Usually, for errors Eclipse finds, you can
rt-click the red-X, click Quick Fix, and Eclipse will prompt you for options to
repair errors. In this case, you need to
add imports for Container and GridLayout.
public GPA_Application(){
super("GPA Calculator");
//build
widgets
addGrade=new JButton("enter grade");//put text on button
reset=new JButton("reset");//put text on button
gradeField=new JTextField(20);//many constructors...this
one sets width
gradeLabel=new JLabel("enter grade here:");
gpaLabel=new JLabel("GPA: ");
//set
layout
Container c=getContentPane();
c.setLayout(new
GridLayout(3,2));
//add
widgets
c.add(gradeLabel);
c.add(gradeField);
c.add(reset);
c.add(addGrade);
c.add(gpaLabel);
//visibility
setVisible(true);
//screen
position
setBounds(100,100,500,500);
//closing
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
Add
one line to your main method:
public static void main(String[] args) {
GPA_Application
myApp=new GPA_Application();
}
If
you have no errors, you can save and run this now.
Yikes! Too scary?
Putting JPanels on the different sections, and putting our buttons,
labels, and textfields on the panels would add a layer of complexity in
exchange for a more elegant look and no more functionality. Here’s some code you can paste into your
constructor to replace the part where the widgets are currently added:
JPanel
one, two, three;
one = new
JPanel();
two = new
JPanel();
three = new JPanel();
c.setLayout(new GridLayout(3, 1));
// one.setLayout(new GridLayout(1, 2));
// two.setLayout(new GridLayout(1, 2));
//
add widgets
//
c.add(gradeLabel);
one.add(gradeLabel);
one.add(gradeField);
//
c.add(gradeField);
c.add(one);
//
c.add(reset);
//
c.add(addGrade);
two.add(reset);
two.add(addGrade);
c.add(two);
three.setBackground(Color.WHITE);
three.add(gpaLabel);
c.add(three);
This
improves the look somewhat. We could
provide a textfield for the GPA and not allow editing and this might help, but
we’ll live with what we’ve got.
Buttons
currently have no functionality. That’s
next. We need to implement the
ActionListener interface and add the appropriate method (actionPerformed). Stubbing in functionality is a common
activity in software development.
Initially, we will simply have buttons display their name in the GPA
label. We can add computations
later. When you modify your class to
implement ActionListener, (below) Eclipse shows an error (a red bubble with an
X on it).
public class GPA_Application extends JFrame implements ActionListener {
Rt-click
the error bubble and select quick fix. Select “add the import for
ActionListener”. But there’s still an error.
Rt-click again and select quick-fix “add unimplemented methods”. Eclipse will stub in the required method for
ActionListener interface:
public void actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
}
Although
we can again run our app, it will not do anything for text entry or button click,
because buttons are not listening for clicks and we’ve got no functionality
coded in our actionPerformed method. To
get the buttons listening, after building them in the frame’s constructor
(calling their constructors with new),
add the actionListener to them. The
keyword this is also used in C++ in a similar way: this is a
self-referential pointer, referring to our frame, in this case. Our frame will implement the ActionListener
interface and describe what action to take when buttons are fired.
addGrade.addActionListener(this);
reset.addActionListener(this);
If
you put these two lines (above) before you build your buttons (new JButton…)
you’ll get a null pointer exception when you run your app. Note that it is not
particularly good practice, or common programming practice, to use this
class to implement the listener. Usually
another class would handle the events.
Just
to practice stubbing, I’ll echo the button name to the GPA label field when a
button is clicked. Revise
actionPerformed method to look like this:
public void actionPerformed(ActionEvent e)
{
String buttonName=e.getActionCommand();
gpaLabel.setText(buttonName);
}
Now,
when you press a button, the button name is echoed in the gpa label. Our stub works as we wished. Good programming
practice is to always have a running application, even if all functionality has
not been implemented. Do not go home leaving a broken app. Designing and
developing so that you always have a “working” app requires programming
discipline. Do not code more than a line or two at a time if the IDE is showing
errors, for example.
But
since our stub works, if we were at the office and it was 5pm, we might go home
now. But we’d like to get our app
finished so we will add some more code.
Let’s
do the math.
To
calculate a gpa, we need to count grades entered. Our counter should be initialized to 0 in the
constructor, and again if the reset button is pressed. We need to keep a tally of the total
gradepoints entered up to the given moment (currentSum). (In this simple app,
each course carries the same credits. A slightly more sophisticated version
would allow entry of credits per course.)
Since currentSum is a sum it also would need to be initialized and
reset. We need to get the letter that
has been entered. Convert letter to a
number value. Add it to our gradepoint
sum variable. Divide by count and display. Be sure not to divide by 0!!! That is a
runtime exception.
When
and where does all this happen?
In
constructor, initialize sum and count variables, which must be fields, since
more than one method must access them.
If
reset is pressed, reinitialize sum and count variables and clear gpa label and
gradefield. (in actionPerformed)
If
addGrade button is pressed, get the input, convert to a letter (char), figure
out what grade value this char has, add it to the currentSum, divide by count
and display gpa (in actionPerformed)
Got
it? OK. We still haven’t seen how to
handle buttons in actionPerformed. If there were only one button, no control
would be needed. For multiple buttons, we need control – an if else
structure. The ActionEvent carries
information about the event that fired this action. We can interrogate it. You can go too the Javba API and see all its
fields and methods. The method getSource
returns the name of the widget that fired the event, the method
getActionCommand returns the text on the widget.
Here’s
my first revision:
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==reset){
//code here
}
else{//other button code here
}
}
Here’s
my entire program, minus the part to calculate how many points are assigned for
each letter. Remember we looked at that process when we reviewed the switch statement.
Notice, I called a function to get the grade value of the text entered, rather
than calculating it inside my actionPerformed.
“Don’t clutter your code up” is the rule here.
6.
Example
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JLabel;
public class GPA_Application extends JFrame implements ActionListener {
private double gpa;
private int gradeCount;
private double currentSum;
private JButton addGrade, reset;
private JTextField gradeField;
private JLabel gradeLabel;
private JLabel gpaLabel;
public GPA_Application() {
super("GPA Calculator");
//
build widgets
addGrade = new JButton("enter grade");// put text on button
reset = new JButton("reset");// put text on button
gradeField = new JTextField(20);// many constructors...this
one sets
// width
gradeLabel = new JLabel("enter grade here:");
gpaLabel = new JLabel("GPA: ");
//
set layout
Container c = getContentPane();
c.setLayout(new GridLayout(3, 2));
//
add widgets
c.add(gradeLabel);
c.add(gradeField);
c.add(reset);
c.add(addGrade);
c.add(gpaLabel);
//
get buttons listening
addGrade.addActionListener(this);
reset.addActionListener(this);
//
visibility
setVisible(true);
//
screen position
setBounds(100, 100, 500, 500);
//
closing
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
GPA_Application myApp = new GPA_Application();
}
@Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == reset) {
gpaLabel.setText("GPA:");
gradeCount
= 0;
currentSum
= 0;
gradeField.setText("");
} else
{// other button code
here
double
value = getValue(gradeField.getText());
currentSum+=value;
gradeCount++;
double gpa=currentSum/gradeCount;
gpaLabel.setText("GPA: "+gpa);
}
}
double getValue(String s) {
char letter=s.charAt(0);
/*
modify switch statement code from day1-morning to go here*/
return 4.0;
}
}
Exercises
1.
Complete and test Example 9.
2.
Add another label and textfield and upgrade the app to allow for different
credit loads for each course.
Can we get that getValue method
working and complete the app? Look up
above for the switch statement and modify it.
What
were the lessons in Example 12? Subclassing JFrame. Constructors can be long and
complicated. An app may have many
imports. We Implemented the ActionListener interface. We studied what should be a field value and
what can be local to a method. We saw where to put field variables. Look at our main. What happened there? We had to instantiate
our application with a call to its constructor.
We had a little practice with grid layout and some practice making
widgets. We learned what a stub was. Along with systematic testing, stubs and
drivers are the bread and butter of large app development. What’s a stub? What’s a driver?