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

Different sorts of Java classes

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.

Some background on OOP/OOD

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.

When To Use Interfaces

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.

When To Use Abstract classes

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.

When to Use Both

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)

Aside on Data Encapsulation and OOP in Java

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.

Rounded Rectangular Callout: Data access
 


 

Oval: Class A
 

 

 

 

 

 


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.

Object instantiation

 

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.

Object References:

 

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. 

More about Classes and Objects: Access Control, public and private visibility, method overloading

 

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?