Software Design/Construction -- Week 12

Introduction

This week we will look at graphical user interface programming in Java.

Note that the links from this page are to handouts that will be distributed the night of class.  Only print out those handouts if you could not attend class.

Main topics this week:

Advanced Language Concepts Assignment Due
Applet Assignment Assigned
GUI Programming
Java Applets & Applications
Applets
Applet Security
Running an Applet
Example Applet
Graphical User Interfaces
AWT
AWT Components
Component Interaction
Layouts and Layout Managers
AWT versus Swing
Application versus Applet
Using JFrame
Using JPanel
Using JDialog
Using JLabels
Using JButtons
Using JTextField
Using JList
Using JTabbedPane
Using JTable
Events and EventListeners
Output to User in GUIs
Example Swing Applet
Next Week

Advanced Language Concepts Assignment Due

Your binary search tree assignment is due this week.

Applet Assignment Assigned

The applet assignment is assigned this week, and is due week 14.  Note that in the assignment, you are creating two applets.  One is to be coded by hand, the other using the IDE.  Both applets solve the same problem.

GUI Programming

Graphical User Interface programming is the way you write code that displays windows to the user.  Instead of typing on a keyboard, the user can use the mouse to interact with radio buttons, check boxes, etc.  While this makes things easier for the user, it makes it more difficult for the programmer.

We'll look at GUI programming in Java, because there are no standard classes for GUI programming in C++.  If you want to program graphical user interfaces in C++, you need to have a set of classes called a GUI framework.  There are many C++ GUI frameworks available, some free, some commercial.

Java Applets & Applications

So far, the Java programs you have written have all been applications.  A Java application is a class that has a main method, and you run it using the "java" command. 

A Java applet is a class that extends the java.applet.Applet class.  This class is not run by using the "java" command, but instead is run by a web page by including the appropriate line of HTML.   The applet uses a portion of the web page in which to display results, instead of having a window of its own. 

Thus, Java applications are useful for non-web based programs, and applets are useful for programs that are to be embedded in web pages. 

Applets are stored on the web server, but are downloaded and run on the client.   

Applets

Since applets are stored on the web server and downloaded to the user's machine, they are useful for programs that may change frequently.   Each time the user visits the page, they will download the latest version of the program.  However, since they are downloaded, the applet should not be large or the user will spend a lot of time waiting for the download each time they visit the page.  

Applets do not have a main method.  Instead, they have methods called by the web browser.  Here are the important methods in Applet that you may need to override in your applet class:

void init () -- This is called when the browser loads the applet into memory.  If your applet uses multihreading, this is an appropriate place to create threads.  This is also the place to setup the user interface (which we'll talk more about later).

void destroy () -- This is called just before the browser unloads an applet from memory.  If you created anything in the init method, this is the place to destroy it. 

void start () -- This method is called whenever the applet becomes visible to the user.  It may be called many times.  You may want to create threads that involve user visible effects here. 

void stop () -- This method is called whenever the applet becomes invisible to the user.  It may be called many times.  You may want to stop threads that involve user visible effects here.

String getAppletInfo () -- This method should be overridden to provide information about the author, version, and copyright of the applet (and any other information you want to provide).

String [][] getParameterInfo () -- This method returns information about parameters that are meaningful to the applet.  Parameters can be used to modify some aspect of the applet's operation.  Applets do not need to support any parameters.   See the Java API documentation for details on what the two-dimensional array returned by this method should look like.

Let's look at the life cycle of an applet.  The user goes to the web page of the applet.  The applet is downloaded and loaded into memory, and the init method called on it.  As soon as the applet becomes visible to the user (say, the user scrolls the web page so the applet is showing), the start method is called.  If the applet becomes invisible (say, the user scrolls the web page so the applet is not showing, or minimizes the browser), the stop method is called.  Eventually, the user closes the browser and the applet's destroy method is called just before it is unloaded from memory.

Applet Security

Since an applet is downloaded from a web site and run on your local machine, there is a huge issue with security.  Most people know to not run programs that are sent to them through email, but with an applet you're running a program sent to you through a web page.   Without any security in place, and applet could do something like delete all the files from your hard drive. 

To prevent things like that, applets have restrictions on what they can do:

Some of these restrictions can be removed if you choose to allow applets to do more things on your machine (by changing settings in your web browser).  By default, though, you cannot expect an applet you are writing to be able to overcome these restrictions.

Running an Applet

There are two ways to run an applet.  One is to embed the applet in a web page.   The other is to use the Java Applet Viewer, which comes with the Java Development Kit.  The Java Applet Viewer is used to test applets, but it is not as good of a test as actually using a web browser. 

To embed an applet in a web browser, you need to add in an HTML tag to your web page that tells the web browser which applet to run, and how much room on the web page to give it.  The tag used is <applet>.  For example:

<applet code="comp345.lab4.MyApplet" width=300 height=300>
</applet>

This tells the web browser to download the class "comp345.lab4.MyApplet" and run it in an area of the screen that is 300 pixels wide by 300 pixels high.

We had said earlier that you could specify parameters to change the behavior of the applet, if the applet supported parameters.  You can do that by using the <param> tag.  For example:

<applet code="comp345.lab4.MyApplet" width=300 height=300>
<param name="background" value="blue">
<param name="animation" value="dancing clown">
</applet>

The applet itself would need to use the getParameter method to get the value for a given parameter.  For example, in the applet, to see the value for the background parameter:

String value = getParameter ("background");

If the given parameter was not set in the applet tag, then getParameter would return a null reference.

Using parameters, then, allows the web page to control certain aspects of the applet's operation. 

Example Applet

Let's look at a very simple Applet that just displays "Hello World!".  A lot of this code will not make sense yet, since it deals with graphical user interfaces.   We'll talk more about that next.

package comp345.applet;

import java.awt.*;

public class ExampleApplet extends java.applet.Applet
{
  public void init()
  {
    setLayout (new BorderLayout ());
    add (new Label ("Hello World!"), BorderLayout.CENTER);
  }
}

Now we need a web page for the applet:

<html>
<head>
<title>Example Applet</title>
</head>
<body>
<applet code="comp345/applet/ExampleApplet.class" width=300 height=300>
</applet>
</body>
</hmtl>

Note that the root of the applet package directory structure must be the same directory where the web page resides.  So if the web page is in, on einstein, ~shaffsta/public_html/cs345, then the applet class file ExampleApplet.class would need to be in ~shaffsta/public_html/cs345/comp345/applet. 

Let's see what this applet does when we run it (the web page is at http://cs.franklin.edu/~shaffsta/cs345/example.htm).

Graphical User Interfaces

Applets must interact with the user using a graphical user interface (GUI).  In Java, there are several ways of doing GUIs. 

AWT

AWT stands for Abstract Windowing Toolkit, and is the original way of doing graphical user interfaces in Java.  Since AWT is old, it is supported by all web browsers. 

Swing

Swing is a newer windowing toolkit.  It is supported by some web browsers, but not all of them.  The best way to know if Swing is supported by a web browser is to write an applet using Swing and try to run it.   Swing uses the AWT classes as a base.

Java2D

Java2D is a set of classes that provides powerful support for two dimensional graphics and images. 

Drag & Drop

The Drag & Drop classes provide support for dragging objects from one program to another.  There is limited support for dragging and dropping between a Java program and a non-Java program.

Accessibility

The Accessibility classes provide support for alternative user input and output devices.  For example, a device to read the screen to a blind person.  This support is built into Swing and AWT.

Collectively, these are all called the Java Foundation Classes.

AWT

Both Swing and AWT use the same basic architecture, so we'll look at building GUIs with AWT.  You can easily switch to using Swing by using a different set of classes that provide similar functionality.

An AWT GUI consists of the following pieces:

containers -- A container is a graphical component that can hold other graphical components.  For example, a window is a container since it can have other components inside of it.

components -- Anything that can be put into a container is a component.  These include buttons, check boxes, radio buttons, input fields, static text, images, shapes, etc.

layout managers -- A container can be given a layout manager.  A layout manager takes care of moving components around as the container is resized.  We'll talk more about layout managers in just a bit.

events -- A GUI in Java is called "event driven".  This means that you don't have a while loop that waits for user input, like in your menu driven client.  Instead, Java takes care of waiting for the user to click a button or type something into an edit field, and it calls methods on your classes when something  happens.  There are many events that can happen in a GUI, and learning how to use events is a big part of writing GUIs.

event listeners -- If an event happens and nobody is listening, nothing gets done.  An event listener is a piece of code that handles specific events.  For example, you may have a method that is designed to handle when a particular button is pressed.  To have a method handle a particular event, that method must register itself as being interested in handling that event.

We'll talk more about each of these pieces in more detail.

AWT Components

As you start looking at the Java API documentation for the various AWT containers and components, you'll see that they all them inherit from java.awt.Component.  That is the base class for anything in Java that can be displayed on the screen.  Many of the methods we will discuss later actually live in the Component class.

Containers are a special kind of component that can hold other components.  A window is an example of a container.  All containers inherit from java.awt.Container (which, in turn, inherits from java.awt.Component).   Thus, a container can hold other components, which may be other containers.

Types of Containers

java.awt.Frame is a container that represents a window with a title bar and border, along with possibly a menu.  This is typically what you use as the main window in your application. 

java.awt.Dialog is a container that represents a window with a title bar and border.  This is typically used to get input from the user that the application needs to continue (for example, a login id and password screen).  

java.awt.Panel is a container that must be placed inside of another container.  Panels can be used to organize components in order to get exactly the sort of visual effect you want.  We'll see some examples of this later.

In any container, to add a component to the container, you use the add method for the container and pass in the component to add.

Types of Components

java.awt.Button represents a button the user can click.

java.awt.Checkbox represents a check box. 

java.awt.Choice represents a popup menu from which the user can select one of many choices.

java.awt.Label represents static text (text that is simply visible to the user, but will not react to the user clicking on it). 

java.awt.List represents a list of choices.  This is different from java.awt.Choice, in that multiple items from the list can be visible even when the user is not selecting an item.

java.awt.TextField represents an edit area where the user can type in a line of text.

java.awt.Canvas represnts a drawing area.  You will typically use a Canvas in order to have a place to draw when you want to use the Java2D classes.

Component Interaction

It is important to understand how components interact.   In a window, such as a Frame or Dialog, there is something called the focus component.  This is the component that is currently active.  If the focus component is an instance of TextField, then when the user types at the keyboard the keystrokes are sent to the TextField.  If the focus component is an instance of Button, and the user hits the return key, the button will be clicked. 

The user can change the focus component by using the Tab and Shift-Tab keys.  The order in which the focus moves through the components is, by default, the order in which the components were added to the container.  To change the order, when you add the component to the container, specify a last parameter to the add method that tells the order in which the component should get the focus.  For example:

    add (new Button("Press Me"), BorderLayout.CENTER, 5);

Would specify that the button would be the fifth item to get the focus (assuming that no focus numbers were skipped). 

If you want to make a component so that it never receives the focus, you can call setFocusable (false) for that component.   Some components default to not getting the focus (such as Labels), so you could call setFocusable (true) to force them to get the focus if you had a need to do so.

Layouts and Layout Managers

Layout managers control where components appear inside containers.  Most containers have a default type of layout manager, but you can change the layout manager if you want using the setLayout method of the container.   Let's look at a few layout managers.

FlowLayout

A flow layout will put components into the container from left to right, until no more components fit.  Then it will start a new line and continue putting components into the container.  The FlowLayout is the default layout for java.awt.Panel.  Since java.awt.Applet extends Panel, an applet also uses a FlowLayout by default.  Let's look at a sample applet that uses a FlowLayout.

package comp345.applet;

import java.awt.*;

public class ExampleApplet2 extends java.applet.Applet
{
  public void init()
  {
    for (int x = 1; x < 20; x++)
      add (new Button ("Press Me #" + x));
  }
}

The web page for this applet is at http://cs.franklin.edu/~shaffsta/cs345/example2.htm .

The FlowLayout is suitable for simple organizing of components. 

BorderLayout

The border layout allows you to place components in one of five positions in the container.  The positions are named: NORTH, SOUTH, EAST, WEST, and CENTER.  NORTH is at the top of the container, WEST is at the left of the container, and so on. 

You say what position you want a component to use when you call the add method on the container, by passing in a second parameter that is BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST, or BorderLayout.CENTER.

All the items except for the center item will be given exactly as much space in the container as they need.  The center item will get all the rest of the space that is left over.  Let's see an example of putting five buttons into an applet:

package comp345.applet;

import java.awt.*;

public class ExampleApplet3 extends java.applet.Applet
{
  public void init()
  {
    setLayout (new BorderLayout ());

    add (new Button ("North"), BorderLayout.NORTH);
    add (new Button ("South"), BorderLayout.SOUTH);
    add (new Button ("East"), BorderLayout.EAST);
    add (new Button ("West"), BorderLayout.WEST);
    add (new Button ("Center"), BorderLayout.CENTER);
  }
}

Note that since the default layout for an Applet is the FlowLayout, we need to tell the applet to use a new instance of BorderLayout using the setLayout method.

The web page for this is at http://cs.franklin.edu/~shaffsta/cs345/example3.htm .

CardLayout

The CardLayout class allow you to write dialogs that present one screen after another (like a wizard interface).  Each component that is added to the container becomes one screen in a series of screens that are displayed.  You'll only need to worry about this layout manager if you want to program a wizard-like interface.

GridLayout

The GridLayout divides the container into equal sizes squares, and places one component in each square.  You specify the number of row and columns when you create the GridLayout.  For example:

package comp345.applet;

import java.awt.*;

public class ExampleApplet4 extends java.applet.Applet
{
  public void init()
  {
    setLayout(new GridLayout(3,2));
    add(new Button("1"));
    add(new Button("2"));
    add(new Button("3"));
    add(new Button("4"));
    add(new Button("5"));
    add(new Button("6"));
  }
}

The web page for this applet is at http://cs.franklin.edu/~shaffsta/cs345/example4.htm .

GridBagLayout

The GridBagLayout is the hardest layout to use, but also one of the most flexible.   Components are layed out in a grid, but each component may take up multiple squares in the grid.  You shouldn't have to use this for your programming assignment 4, but if you wish to take a look at the java tutorials on using the layout.

SpringLayout

The SpringLayout is another flexible layout manager.  When using the SpringLayout, you specify constraints between components.  For example, you may have a set of three buttons in a row, and you say that you want the distance between the buttons to remain the same, but the distance between the buttons and the edge of the container can increase or decrease as needed. 

SpringLayout is new to version 1.4 of Java, and so may not be supported in browsers yet.  You could, however, use it in your Java applications.

AWT versus Swing

In general, you can use either AWT or Swing for an applet.  You should try a small example applet using Swing, and if your browser successfully displays the applet, you can use Swing.  If your browser does not support Swing, you will need to use AWT.    Here are the primary differences between the two:

Otherwise, you'll find using Swing much the same as using AWT.  Today, we'll focus on how to use various Swing components.

Application versus Applet

It is very easy to write code that can run in either an applet or an application.    Consider if you were to write a class that extended JPanel (a Swing container), and put all your GUI components into that panel.  Your applet, then, would simply need to add that JPanel to itself.  For example:

public class AppletExample extends JApplet
{
  public void init ()
  {
    setLayout (new BorderLayout ());
    getContentPane ().add (new MYJPanel (), BorderLayout.CENTER);
  }
}

The MyJPanel class would contain all the code to actually do the work of the applet.    Given that, you could easily write an application to do the same thing:

public class ApplicationExample
{
  public static void main (String [] args)
  {
    JFrame myFrame = new JFrame ("An Application");

    myFrame.getContentPane ().add (new MYJPanel (), BorderLayout.CENTER);
    myFrame.setVisible (true);
  }
}

Since all the actual work is done in the MYJPanel class, both applet and application simply need to create one and add it to themselves. 

Note that this does become a little more complicated if you want your applet or application to contain a menu.  You must add the menu directly to the JApplet or the JFrame.  

Using JFrame

JFrame is the Swing version of Frame, and is a top level window.  This kind of container cannot be put into other containers, and will only be used as part of an application.  The default layout manager for JFrame is BorderLayout.  The JFrame starts out invisible, so when you are done adding things to it, you must call "setVisible (true)" on it to show it.  Since this is a Swing component, you add other components to it using "getContentPane ().add". 

Some useful JFrame methods:

void setDefaultCloseOperation (int operation) -- This tells the JFrame what to do when the user tries to close the window.  Options are: JFrame.DO_NOTHING_ON_CLOSE, JFrame.HIDE_ON_CLOSE, JFrame.DISPOSE_ON_CLOSE, JFrame.EXIT_ON_CLOSE.  The main window for your application typically is set to JFrame.EXIT_ON_CLOSE. 

void setJMenuBar (JMenuBar menu) -- This tells the JFrame what set of menus to use. 

Using JPanel

JPanel is a container that must be placed inside of another container to be used.    You will usually use this by writing a class that extends JPanel, and adding components to the JPanel in the constructor of that class.  JPanels are usually used to organize other components to create more sophisticated screens (by mixing and matching layout managers as we saw last week).

Note that even though this is a Swing container, you do not use getContentPane.    Just use "add" normally.

Using JDialog

JDialog is used to prompt the user for information.  The dialog can be modal or non-modal.  A modal dialog means that the user must finish with the dialog before doing anything else.  A non-modal dialog means that the user does not need to finish with the dialog before doing anything else.  Since this is a Swing component, you add other components to it using "getContentPane ().add".

Swing provides a class that makes displaying simple dialogs easier.  This class is called JOptionPane.  For example, to ask the user to input a student name, you could use:

String name = JOptionPane.showInputDialog (this, "Enter student name");

The first parameter to showInputDialog should be a container that represents the parent of the dialog shown. 

You can also use showMessageDialog that simply displays a message to the user and allows them to click and OK button.  If you want to display a message and allow them to click Yes, No, or Cancel, use showConfirmDialog. 

You can further customize the look of the JOptionPane dialogs by using the more complicated versions of the above methods.

Using JLabels

JLabel is the class you use when you simply want text to appear at some place on the screen.  You can set the text of the JLabel when you create the label, or you can use the "setText" method to change the text after the label is created. 

By default, JLabel will start text at the left edge of the label.  If you want it centered, or right aligned, you need to use the  "setHorizontalAlignment" method (see the API documentation for details). 

Using JButtons

JButton is the class you use when you want the user to be able to click a button.    You usually pass the button text to the JButton when you create it.  So to create a button that has the text "Push Me" on it, you would use:

JButton button = new JButton ("Push Me");

A button needs to be added to a container before the user can actually push it. 

You can enable and disable buttons based on conditions in the program.  You'll use the "setEnabled" method, passing in "true" to enable the button and "false" to disable the button.  A disabled button will be displayed with grey text, showing the user that it cannot be pushed. 

A button that is the default button usually has a thick black border around it, and will act as if the user had clicked it whenever the user hits the return key when the window or dialog has focus.  You set a default button by calling, on the frame or applet:

getRootPane ().setDefaultButton (button);

Eventually the user is going to click the button, and you need to have code that will handle it.  Your code for handling the button press must be in a class that implements the ActionListener interface.  The ActionListener interface has one method:

void actionPerformed (ActionEvent e) -- The ActionEvent passed in will tell you which button was pressed, by calling e.getActionCommand ().  This will return the text of the button that was pressed.  You can also call e.getSource (), which will return the actual instance of the Object that caused the event to happen (in the case of a button press, it will return the JButton instance of the button that was pressed). 

Here's an example of an applet that responds to simple button presses:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class ButtonApplet extends JApplet implements ActionListener
{
  JLabel label = new JLabel ();

  public void init ()
  {
    JButton temp;

    getContentPane ().setLayout (new BorderLayout ());

    temp = new JButton ("North");
    temp.addActionListener (this);
    getContentPane ().add (temp, BorderLayout.NORTH);

    temp = new JButton ("South");
    temp.addActionListener (this);
    getContentPane ().add (temp, BorderLayout.SOUTH);

    temp = new JButton ("West");
    temp.addActionListener (this);
    getContentPane ().add (temp, BorderLayout.WEST);

    temp = new JButton ("East");
    temp.addActionListener (this);
    getContentPane ().add (temp, BorderLayout.EAST);

    label.setHorizontalAlignment (JLabel.CENTER);

    getContentPane ().add (label, BorderLayout.CENTER);
  }

  public void actionPerformed (ActionEvent e)
  {
    label.setText (e.getActionCommand ());
  }
}

Note that you need to import java.awt.event.* to use ActionListener and ActionEvent, and java.awt.* to use BorderLayout.

If your browser supports Swing applets, you can see this in action at http://cs.franklin.edu/~shaffsta/cs345/buttonexample.htm .  If your browser does not support Swing applets, you need to get the latest version of Sun's Java Plug-In for your browser.

Using JTextField

JTextField is the class you use when you want the user to be able to type in a single line of text.  There are some constructors you can use:

JTextField (int columns) -- This constructor allows you to pass in the number of columns that should be visible in the text field. 

JTextField (String text, int columns) -- This constructor allows you to pass in the number of columns that should be visible in the text field, along with text that will be in the text field.

To see what text the user has typed into the text field, use the "getText" method. 

There's a version of JTextField that will allow the input of formatted information, such as a date.  It's called JFormattedTextField.  You create it by passing it an object of the type you want it to use as a format, such as a Date instance.  For example:

JFormattedTextField field = new JFormattedTextField (new Date ());

This field will now only accept dates of the form "mmm dd, yyyy". 

You can also find on the Internet graphical calendars for choosing dates (search for JCalendar to find a popular one). 

Using JList 

JList is the class you use when you need a list of multiple items to display to the user.  The JList has been designed so that the JList is only the visible portion of the list.  The actual data is stored in a ListModel.  ListModel is an interface that you can implement, if you want, to create your own list models.  However, you can also just pass in a Vector of Objects to JList and tell it to use that as the data to display.  For example:

JList list = new JList ();
Vector v = new Vector ();

v.add (new Student (98, "John Smith"));
v.add (new Student (303, "Jennifer Jones"));

list.setListData (v);

Note that you store Objects into the Vector, and then the list will display whatever is returned from the Object's toString method.  You can customize the display by writing a class that implements CellRenderer, but that's beyond the scope of what's needed for this course.  Look at the API documentation for JList to see an example, and the Sun tutorials, if you're interested in seeing how it works.

Every time you call setListData, you will completely replace the existing data in the list. 

The default JList does not handle scrolling of the list if there are too many items in it.  To scroll a list, you must place it into a JScrollPane.  Then the JScrollPane would be placed into the container where you want the list to appear.    For example:

JScrollPane scroll = new JScrollPane (list);

getContentPane ().add (scroll, BorderLayout.CENTER);

The default JList will allow the user to select multiple items from the list.  If you only want them to be able to select single items, you would call "list.setSelectionMode (ListSelectionModel.SINGLE_SELECTION)".  To see what is selected, you can use "list.getSelectedValue" for single selection, or "list.getSelectedValues" for multiple selection.

Let's see an example of an applet that allows us to add items to a list by typing them into a text field.  We'll also see how to get a selected item out of the list.

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;

public class ListApplet extends JApplet implements ActionListener
{
  JLabel label = new JLabel ();
  JTextField textField = new JTextField (30);
  JList list = new JList ();
  Vector v = new Vector ();

  public void init ()
  {
    JButton temp;
    JPanel panel = new JPanel ();

    getContentPane ().setLayout (new BorderLayout ());

    temp = new JButton ("Add");
    temp.addActionListener (this);
    panel.add (temp);

    temp = new JButton ("Display");
    temp.addActionListener (this);
    panel.add (temp);

    getContentPane ().add (panel, BorderLayout.WEST);

    label.setHorizontalAlignment (JLabel.CENTER);
    getContentPane ().add (label, BorderLayout.SOUTH);

    getContentPane ().add (textField, BorderLayout.NORTH);

    list.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);
    JScrollPane scroll = new JScrollPane (list);
    getContentPane ().add (scroll, BorderLayout.CENTER);
  }

  public void actionPerformed (ActionEvent e)
  {
    if (e.getActionCommand ().equals ("Add"))
    {
      v.add (textField.getText ());
      list.setListData (v);
    }
    else if (e.getActionCommand ().equals ("Display"))
    {
      label.setText (list.getSelectedValue ().toString ());
    }
  }
}

This example applet can be found at http://cs.franklin.edu/~shaffsta/cs345/listexample.htm.

There are many more things you can do with JList, including writing code that reacts when the user changes the selection (see addListSelectionListener), and writing code that reacts when the user double clicks on an item in the list (see the JList API docs for an example in the overview section). 

Note that if you want to modify the contents of the list without completely replacing the list every time, you need to write a list model.  A list model is a class that holds the contents of the list, and implements the ListModel interface.  If you call JList.setListData, the JList will create a list model from the vector you pass into it.  

You can also change the way list items draw themselves, by providing instances of classes that implement the ListCellRenderer interface.  This allows you to display mixed text and graphics, such as in Windows explorer. 

Using JTabbedPane

JTabbedPane can be used to display tab controls.  A tab control is a way of presenting a lot of information in a single screen, with information grouped into tabs.    A single tab displays at a time.  You add a JTabbedPane instance into a container, and add tabs to the JTabbedPane using the addTab method.  Usually, what you add to the tab is a panel that contains everything you want to appear on the tab.   

Here's an example applet that uses JTabbedPane:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;

public class TabbedApplet extends JApplet implements ActionListener
{
  JLabel label = new JLabel ();
  JTextField textField = new JTextField ("<Enter new item here>");
  JList list = new JList ();
  Vector v = new Vector ();

  public void init ()
  {
    JButton temp;
    JPanel panel = new JPanel ();
    JTabbedPane tabbedPane = new JTabbedPane ();

    getContentPane ().setLayout (new BorderLayout ());

    temp = new JButton ("Add");
    temp.addActionListener (this);
    panel.setLayout (new GridLayout (2, 1));
    panel.add (textField);
    panel.add (temp);

    tabbedPane.addTab ("Add Item", panel);

    panel = new JPanel ();

    temp = new JButton ("Display");
    temp.addActionListener (this);
    panel.setLayout (new GridLayout (2, 1));
    panel.add (temp);
    label.setHorizontalAlignment (JLabel.CENTER);
    panel.add (label);

    tabbedPane.addTab ("Display Item", panel);

    getContentPane ().add (tabbedPane, BorderLayout.NORTH);

    list.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);
    JScrollPane scroll = new JScrollPane (list);
    getContentPane ().add (scroll, BorderLayout.CENTER);
  }

  public void actionPerformed (ActionEvent e)
  {
    if (e.getActionCommand ().equals ("Add"))
    {
      v.add (textField.getText ());
      list.setListData (v);
    }
    else if (e.getActionCommand ().equals ("Display"))
    {
      label.setText (list.getSelectedValue ().toString ());
    }
  }
}

This applet can be executed at http://cs.franklin.edu/~shaffsta/cs345/tabbedexample.htm if your browser supports Swing.

Using JTable

A JTable represents the display of information by rows and columns, like a spreadsheet.   You can create a JTable by providing a two-dimensional vector of data, and a vector containing the names of the columns in the table.  Similar to a JList, though, if you want to modify the data then you would need to provide an instance of a class that implements TableModel. 

To make implementing a TableModel easier, Java provides AbstractTableModel. This is a class that implements TableModel, and can be inherited from.  When you inherit from AbstractTableModel, you reduce the number of methods you must write to get a table model working.  Here are the minimum methods you need to override from AbstractTableModel:

public int getRowCount () -- you must override this method to return the number of rows in the data.  This implies that you are storing the data in some way, possibly in a two-dimensional vector.

public int getColumnCount () -- you must override this method to return the number of columns.  This value should not usually change.

public Object getValueAt (int row, int column) -- you must override this method to return the object at the specific row and column.  You'll look it up in your data storage.

You may also need to provide methods on your table model for modifying the data, if your application needs them.  If you have methods for modifying the data, then in each method that modifies the data, you will want to call the fireTableDataChanged method in the AbstractTableModel you have inherited.  This will update the on-screen data being displayed.  There are a variety of fireXXX methods you can call for different situations...until you call one of these methods, the on-screen appearance will not change.

Events and EventListeners

We've seen a simple example of an event listener in the JButton example.  In general in Java, anything the user can do with the user interface will generate an event, and you can write an event listener to run code when that event happens.  Event listeners are often anonymous inner classes.  For example, the JButton example could have been written like this:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class ButtonApplet extends JApplet
{
  JLabel label = new JLabel ();

  public void init ()
  {
    JButton temp;

    getContentPane ().setLayout (new BorderLayout ());

    temp = new JButton ("North");
    temp.addActionListener (new ActionListener ()
    {
      public void actionPerformed (ActionEvent e)
      {
        label.setText (e.getActionCommand ());
      }
    });

    getContentPane ().add (temp, BorderLayout.NORTH);

    temp = new JButton ("South");
    temp.addActionListener (new ActionListener ()
    {
      public void actionPerformed (ActionEvent e)
      {
        label.setText (e.getActionCommand ());
      }
    });

    getContentPane ().add (temp, BorderLayout.SOUTH);

    temp = new JButton ("West");
    temp.addActionListener (new ActionListener ()
    {
      public void actionPerformed (ActionEvent e)
      {
        label.setText (e.getActionCommand ());
      }
    });

    getContentPane ().add (temp, BorderLayout.WEST);

    temp = new JButton ("East");
    temp.addActionListener (new ActionListener ()
    {
      public void actionPerformed (ActionEvent e)
      {
        label.setText (e.getActionCommand ());
      }
    });

    getContentPane ().add (temp, BorderLayout.EAST);

    label.setHorizontalAlignment (JLabel.CENTER);

    getContentPane ().add (label, BorderLayout.CENTER);
  }
}

In this version, all the listeners are anonymous inner classes.  For this example, using anonymous inner classes means we have duplicated code, so we would use a member inner class instead.  But for an example where each of the buttons did something different when they were pressed, anonymous inner classes would work, too. 

Here are some of the events that can be listened on:

ActionEvent -- Button presses mainly

ComponentEvent -- A component was resized, moved, hidden, shown

FocusEvent -- A component gets or loses the focus

ItemEvent -- An item in a list was selected or deselected, or a checkbox or radio button was selected or deselected

KeyEvent -- User has typed keystrokes when the focus is on the component

MouseEvent -- A mouse button was clicked, or the mouse cursor entered or left the component

MouseMotionEvent -- The mouse cursor moved, or was dragged, in the component

TextEvent -- When a text component's text is changed

WindowEvent -- The window was opened, closed, minimized, maximized, etc

Some of the listeners for these events have multiple methods in them.  For example, the MouseListener interface has these five methods:

mouseClicked
mouseEntered
mouseExited
mousePressed
mouseReleased

Many times you only care about one of the methods, such as mouseClicked, but you must implement all the methods in the interface.  To make this job easier, Java provides event adapters.  The MouseAdapter class implements all the methods in the MouseListener interface, but each method does nothing.  You can then extend MouseAdapter and override only those methods you care about.  For example:

public class A extends MouseAdapter
{
  public void mouseClicked (MouseEvent e)
  {
    label.setText ("Clicked!");
  }
}

This allows you to handle the specific methods you want to handle without needed to implement the other methods as well.

Output to User in GUIs

One important point to keep in mind when writing a GUI application, is that any output to the user must be through the graphical user interface.  System.out.println should be reserved for debugging output only.  The user will usually not see any text output, they will only see the graphical user interface.

When you run a GUI Java program using the "java" command, you will see both the graphical user interface, and a text console.  Any exceptions will be displayed in the text console.  Usually, when your users are running your program, you do not want the text console displayed. 

To run a GUI Java program without showing the text console, you can use the "javaw" command instead of the "java" command.  "javaw" takes the same command line arguments as "java".  This works on Windows machines only. 

Example Swing Applet

An example applet showing most components available in Swing is at http://java.sun.com/products/plugin/1.4.2/demos/jfc/SwingSet2/SwingSet2.html .  This applet is quite large and will take a minute or so to download.

Next Week

Next week we will look at using an IDE for graphical user interface programming in Java.