The Artima Developer Community
Sponsored Link

Objects and Java Seminar
Events, GUIs, and Swing
Lecture Handout

Agenda


Java's Event Model


Event Model Concepts


Event Generator Idiom


Step 1. Define Event Category Classes

1 // In file eventgui/ex1/TelephoneEvent.java
2 public class TelephoneEvent
3     extends java.util.EventObject {
4
5     public TelephoneEvent(Telephone source) {
6         super(source);
7     }
8 }

Step 2. Define Listener Interfaces

1 // In file eventgui/ex1/TelephoneListener.java
2 public interface TelephoneListener
3     extends java.util.EventListener {
4
5     void telephoneRang(TelephoneEvent e);
6
7     void telephoneAnswered(TelephoneEvent e);
8 }

Step 3. Define Adapter Classes (Optional)

1 // In file eventgui/ex1/TelephoneAdapter.java
2 public class TelephoneAdapter implements TelephoneListener {
3
4     public void telephoneRang(TelephoneEvent e) {
5     }
6
7     public void telephoneAnswered(TelephoneEvent e) {
8     }
9 }

Step 4. Define the Event Generator Class

 1 // In file eventgui/ex1/Telephone.java
 2 import java.util.Vector;
 3
 4 public class Telephone {
 5
 6     private Vector telephoneListeners = new Vector();
 7
 8     public void ringPhone() {
 9
10         fireTelephoneRang();
11     }
12
13     public void answerPhone() {
14
15         fireTelephoneAnswered();
16     }
17
18     public synchronized void addTelephoneListener(
19         TelephoneListener l) {
20
21         if (telephoneListeners.contains(l)) {
22             return;
23         }
24
25         telephoneListeners.addElement(l);
26     }
27
28     public synchronized void removeTelephoneListener(
29         TelephoneListener l) {
30
31         telephoneListeners.removeElement(l);
32     }
33
34     private void fireTelephoneRang() {
35
36         Vector tl;
37         tl = (Vector) telephoneListeners.clone();
38
39         int size = tl.size();
40
41         if (size == 0) {
42             return;
43         }
44
45         TelephoneEvent event = new TelephoneEvent(this);
46
47         for (int i = 0; i < size; ++i) {
48
49             TelephoneListener listener =
50                 (TelephoneListener) tl.elementAt(i);
51             listener.telephoneRang(event);
52         }
53     }
54
55     private void fireTelephoneAnswered() {
56
57         Vector tl;
58         tl = (Vector) telephoneListeners.clone();
59
60         int size = tl.size();
61
62         if (size == 0) {
63             return;
64         }
65
66         TelephoneEvent event = new TelephoneEvent(this);
67
68         for (int i = 0; i < size; ++i) {
69
70             TelephoneListener listener =
71                 (TelephoneListener) tl.elementAt(i);
72             listener.telephoneAnswered(event);
73         }
74     }
75 }
76

Step 5. Define Listener Objects

 1 // In file eventgui/ex1/AnsweringMachine.java
 2 public class AnsweringMachine
 3     implements TelephoneListener {
 4
 5     public void telephoneRang(TelephoneEvent e) {
 6         System.out.println("AM hears the phone ringing.");
 7     }
 8
 9     public void telephoneAnswered(TelephoneEvent e) {
10         System.out.println("AM sees that the phone was answered.");
11     }
12 }

 1 // In file eventgui/ex1/Person.java
 2 public class Person {
 3
 4     public void listenToPhone(Telephone t) {
 5
 6         t.addTelephoneListener(
 7             new TelephoneAdapter() {
 8                 public void telephoneRang(TelephoneEvent e) {
 9                     System.out.println("I'll get it!");
10                 }
11             }
12         );
13     }
14 }

 1 // In file eventgui/ex1/Example1.java
 2 public class Example1 {
 3
 4     public static void main(String[] args) {
 5
 6         Telephone ph = new Telephone();
 7         Person bob = new Person();
 8         AnsweringMachine am = new AnsweringMachine();
 9
10         ph.addTelephoneListener(am);
11         bob.listenToPhone(ph);
12
13         ph.ringPhone();
14         ph.answerPhone();
15     }
16 }

Events and the AWT


The AWTEvent Family


Low-Level Event Sources and Listeners


Semantic Event Sources and Listeners


AWT Adapter Classes

All listeners with more than one method have an adapter:


Example: CardLayout Demo Applet


Example: Frames and Dialogs Demo Applet


A Fancier FlowerDemo

 1 // In file EventsGUIs/examples/ex2/FlowerDemo.java
 2 import javax.swing.*;
 3 import java.awt.event.*;
 4
 5 class FlowerDemo {
 6
 7     public static void main(String[] args) {
 8
 9         FlowerFrame bf = new FlowerFrame();
10
11         bf.addWindowListener(
12             new WindowAdapter() {
13                 public void windowClosing(WindowEvent e) {
14                     System.exit(0);
15                 }
16             }
17         );
18
19         bf.pack();
20         bf.setLocation(100, 75);
21         bf.setVisible(true);
22     }
23 }

1 // In file EventsGUIs/examples/ex2/Flowerable.java
2 import javax.swing.ImageIcon;
3
4 interface Flowerable {
5
6     void setFlower(String name, ImageIcon icon, int index);
7 }

  1 // In file EventsGUIs/examples/ex2/FlowerFrame.java
  2 import javax.swing.*;
  3 import java.awt.*;
  4 import javax.swing.border.TitledBorder;
  5 import java.awt.event.*;
  6
  7 class FlowerFrame extends JFrame
  8     implements Flowerable {
  9
 10     private JButton poppyButton;
 11     private JButton flowerButton;
 12     private JMenuItem columItem;
 13     private FlowerSelectionFrame flowerSelFrame;
 14     private int flowerIndex = 19;
 15
 16     FlowerFrame() {
 17
 18         flowerSelFrame = new FlowerSelectionFrame(this);
 19
 20         getContentPane().setLayout(new GridLayout(1, 1));
 21
 22         // Create a JPanel to put on the content pane
 23         JPanel panel = new JPanel();
 24         panel.setLayout(new GridLayout(1, 2, 5, 5));
 25
 26         // set up the buttons
 27         JButton b1 = new JButton("Golden Poppy",
 28             new ImageIcon("images/poppy.gif"));
 29         JButton b2 = new JButton("Columbine",
 30             new ImageIcon("images/columbine.gif"));
 31
 32         b1.setHorizontalTextPosition(JButton.CENTER);
 33         b1.setVerticalTextPosition(JButton.BOTTOM);
 34         b1.setMnemonic('G');
 35         b1.setToolTipText("California");
 36         poppyButton = b1;
 37
 38         b2.setHorizontalTextPosition(JButton.CENTER);
 39         b2.setVerticalTextPosition(JButton.BOTTOM);
 40         flowerButton = b2;
 41
 42         panel.add(b1);
 43         panel.add(b2);
 44
 45         JRootPane root = getRootPane();
 46         root.setDefaultButton(b1);
 47
 48         // Set up the menubar
 49         JMenuBar bar = new JMenuBar();
 50
 51         JMenu flowersMenu = new JMenu("Flowers");
 52         bar.add(flowersMenu);
 53         JMenuItem poppyItem = new JMenuItem("Golden Poppy");
 54         poppyItem.setAccelerator(KeyStroke.getKeyStroke('G',
 55             java.awt.Event.CTRL_MASK, false));
 56         flowersMenu.add(poppyItem);
 57         columItem = new JMenuItem("Columbine");
 58         flowersMenu.add(columItem);
 59         bar.add(flowersMenu);
 60
 61         JMenu lookNFeelMenu = new JMenu("Look&Feel");
 62         JMenuItem metalItem = new JMenuItem("Metal");
 63         lookNFeelMenu.add(metalItem);
 64         JMenuItem motifItem = new JMenuItem("Motif");
 65         lookNFeelMenu.add(motifItem);
 66         JMenuItem windowsItem = new JMenuItem("Windows");
 67         lookNFeelMenu.add(windowsItem);
 68         bar.add(lookNFeelMenu);
 69
 70         root.setJMenuBar(bar);
 71
 72         // Add a border to the content pane
 73         TitledBorder border = new TitledBorder("State Flowers");
 74         border.setTitlePosition(TitledBorder.BOTTOM);
 75         border.setTitleJustification(TitledBorder.RIGHT);
 76
 77         // Define action listeners shared by buttons and
 78         // corresponding menu items (Golden Poppy and Columbine)
 79         panel.setBorder(border);
 80
 81         class ColorAction implements ActionListener {
 82
 83             public void actionPerformed(ActionEvent e) {
 84
 85                 Color c = JColorChooser.showDialog(
 86                     ((Component) e.getSource()).getParent(),
 87                     "Golden Poppy", Color.orange);
 88
 89                 if (c != null) {
 90                     poppyButton.setBackground(c);
 91                 }
 92             }
 93         }
 94
 95         // Define action listeners shared by buttons and
 96         // corresponding menu items (Golden Poppy and Columbine)
 97         panel.setBorder(border);
 98
 99         class FlowerAction implements ActionListener {
100
101             public void actionPerformed(ActionEvent e) {
102
103                 flowerSelFrame.setSelection(flowerIndex);
104                 flowerSelFrame.setVisible(true);
105             }
106         }
107
108         // Add action listeners to the buttons and
109         // corresponding menu items
110         b1.addActionListener(new ColorAction());
111         poppyItem.addActionListener(new ColorAction());
112
113         b2.addActionListener(new FlowerAction());
114         columItem.addActionListener(new FlowerAction());
115
116         // Add action listeners to look & feel menu items
117         metalItem.addActionListener(
118
119             new ActionListener() {
120
121                 public void actionPerformed(ActionEvent e) {
122
123                     try {
124                         UIManager.setLookAndFeel(
125                 "javax.swing.plaf.metal.MetalLookAndFeel");
126                         SwingUtilities.updateComponentTreeUI(
127                             FlowerFrame.this);
128                         SwingUtilities.updateComponentTreeUI(
129                             flowerSelFrame);
130                         pack();
131                     }
132                     catch (ClassNotFoundException e1) {
133                         System.out.println("CNF");
134                         //e1.printStackTrace(System.out);
135                     }
136                     catch (IllegalAccessException e1) {
137                         e1.printStackTrace(System.out);
138                     }
139                     catch (InstantiationException e1) {
140                         e1.printStackTrace(System.out);
141                     }
142                     catch (UnsupportedLookAndFeelException e1) {
143                         e1.printStackTrace(System.out);
144                     }
145                     catch (Exception e1) {
146                         e1.printStackTrace(System.out);
147                     }
148                 }
149             }
150         );
151
152         motifItem.addActionListener(
153
154             new ActionListener() {
155
156                 public void actionPerformed(ActionEvent e) {
157
158                     try {
159                         UIManager.setLookAndFeel(
160                 "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
161                         SwingUtilities.updateComponentTreeUI(
162                             FlowerFrame.this);
163                         SwingUtilities.updateComponentTreeUI(
164                             flowerSelFrame);
165                         pack();
166                     }
167                     catch (ClassNotFoundException e1) {
168                         e1.printStackTrace();
169                     }
170                     catch (IllegalAccessException e1) {
171                         e1.printStackTrace();
172                     }
173                     catch (InstantiationException e1) {
174                         e1.printStackTrace();
175                     }
176                     catch (UnsupportedLookAndFeelException e1) {
177                         e1.printStackTrace();
178                     }
179                 }
180             }
181         );
182
183         windowsItem.addActionListener(
184
185             new ActionListener() {
186
187                 public void actionPerformed(ActionEvent e) {
188
189                     try {
190                         UIManager.setLookAndFeel(
191         "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
192                         SwingUtilities.updateComponentTreeUI(
193                             FlowerFrame.this);
194                         SwingUtilities.updateComponentTreeUI(
195                             flowerSelFrame);
196                         pack();
197                     }
198                     catch (ClassNotFoundException e1) {
199                         e1.printStackTrace();
200                     }
201                     catch (IllegalAccessException e1) {
202                         e1.printStackTrace();
203                     }
204                     catch (InstantiationException e1) {
205                         e1.printStackTrace();
206                     }
207                     catch (UnsupportedLookAndFeelException e1) {
208                         e1.printStackTrace();
209                     }
210                 }
211             }
212         );
213
214         // Lastly, put the panel on the JFrame's content
215         // pane
216         getContentPane().add(panel);
217     }
218
219     public void setFlower(String name, ImageIcon icon, int index) {
220
221         flowerButton.setText(name);
222         flowerButton.setIcon(icon);
223         columItem.setText(name);
224         flowerIndex = index;
225         pack();
226     }
227 }

  1 // In file EventsGUIs/examples/ex2/FlowerList.java
  2 import javax.swing.*;
  3 import java.awt.*;
  4 import java.awt.event.*;
  5
  6 class FlowerSelectionFrame extends JFrame {
  7
  8     private String[] flowerNames = {
  9
 10         "American Beauty Rose",
 11         "Magnolia",
 12         "Hibiscus",
 13         "Bitterroot",
 14         "Iris",
 15         "Black-Eyed Susan",
 16         "Rose",
 17         "Mayflower",
 18         "Peony",
 19         "Wild Rose",
 20         "SunFlower",
 21         "Carnation",
 22         "Pasque Flower",
 23         "Yellow Jessamine",
 24         "Dogwood",
 25         "Lady's Slipper",
 26         "Sego Lily",
 27         "Forget-Me-Not",
 28         "Saguaro Cactus",
 29         "Columbine",
 30         "Mountain Laurel",
 31         "Camellia",
 32         "Violet",
 33         "Rhododendron",
 34         "Lilac",
 35         "Oregon Grape",
 36         "Big Laurel",
 37         "Apple Blossom",
 38         "Pine Cone",
 39         "Cherokee Rose",
 40         "Sage Brush",
 41         "Indian Paint Brush",
 42         "Mistletoe",
 43         "Red Clover",
 44         "Bluebonnet",
 45         "Golden Poppy",
 46         "Peach Blossom",
 47         "Goldenrod",
 48         "OrangeBlossom",
 49         "Hawthorn",
 50         "Yucca",
 51         "Syringa"
 52     };
 53
 54     private String[] flowerImageNames = {
 55
 56         "rose.gif",
 57         "mag.gif",
 58         "hibis.gif",
 59         "broot.gif",
 60         "iris.gif",
 61         "bsusan.gif",
 62         "nyrose.gif",
 63         "mayflower.gif",
 64         "peony.gif",
 65         "wildrose.gif",
 66         "sunflower.gif",
 67         "carnation.gif",
 68         "pasque.gif",
 69         "jessamine.gif",
 70         "dogwood.gif",
 71         "slipper.gif",
 72         "sego.gif",
 73         "forget.gif",
 74         "saguaro.gif",
 75         "columbine.gif",
 76         "mtlaurel.gif",
 77         "camellia.gif",
 78         "violet.gif",
 79         "rhodo.gif",
 80         "lilac.gif",
 81         "grape.gif",
 82         "laurel.gif",
 83         "apple.gif",
 84         "pinecone.gif",
 85         "cherokee.gif",
 86         "sage.gif",
 87         "indian.gif",
 88         "mistle.gif",
 89         "clover.gif",
 90         "bonnet.gif",
 91         "poppy.gif",
 92         "peach.gif",
 93         "goldenrod.gif",
 94         "orange.gif",
 95         "hawthorn.gif",
 96         "yucca.gif",
 97         "mockorange.gif"
 98     };
 99
100     private ImageIcon[] flowerImages = new ImageIcon[42];
101
102     private JList flowerList;
103
104     private Flowerable target;
105
106     FlowerSelectionFrame(Flowerable targetFlowerable) {
107
108         super("State Flowers");
109
110         target = targetFlowerable;
111
112         // Initialize the flower image icons
113         for (int i = 0; i < flowerImages.length; ++i) {
114             flowerImages[i] = new ImageIcon("images/"
115                 + flowerImageNames[i]);
116         }
117
118         // Create a JPanel for the OK and Cancel buttons
119         JButton ok = new JButton("OK");
120         JButton cancel = new JButton("Cancel");
121         JPanel buttonPanel = new JPanel();
122         buttonPanel.setLayout(new GridLayout(1, 2, 5, 0));
123         buttonPanel.add(ok);
124         buttonPanel.add(cancel);
125
126         JPanel southPanel = new JPanel();
127         southPanel.add(buttonPanel);
128
129         // Create list of flowers
130         flowerList = new JList(flowerNames);
131         flowerList.setSelectionMode(
132             ListSelectionModel.SINGLE_SELECTION);
133         flowerList.setCellRenderer(new FlowerCellRenderer());
134         flowerList.setVisibleRowCount(3);
135         JScrollPane pane = new JScrollPane(flowerList);
136
137         // Add action listeners to the buttons
138         ok.addActionListener(
139
140             new ActionListener() {
141
142                 public void actionPerformed(ActionEvent e) {
143
144                     int[] selections =
145                         flowerList.getSelectedIndices();
146
147                     if (selections.length >= 1) {
148                         int i = selections[0];
149                         String text = flowerNames[i];
150                         ImageIcon icon = flowerImages[i];
151                         target.setFlower(text, icon, i);
152                     }
153
154                     setVisible(false);
155                 }
156             }
157         );
158
159         cancel.addActionListener(
160
161             new ActionListener() {
162
163                 public void actionPerformed(ActionEvent e) {
164
165                     setVisible(false);
166                 }
167             }
168         );
169
170         // Put the GUI up on the Frame's content pane
171         getContentPane().setLayout(new BorderLayout());
172         getContentPane().add(southPanel, BorderLayout.SOUTH);
173         getContentPane().add(pane, BorderLayout.CENTER);
174
175         pack();
176     }
177
178     public void setSelection(int index) {
179         flowerList.setSelectedIndex(index);
180     }
181
182     private class FlowerCellRenderer extends JLabel
183         implements ListCellRenderer {
184
185         Color highlightColor = new Color(0, 0, 128);
186
187         FlowerCellRenderer() {
188             setOpaque(true);
189         }
190
191         public Component getListCellRendererComponent(
192             JList list, Object value, int index,
193             boolean isSelected, boolean cellHasFocus) {
194
195             setText(" " + flowerNames[index]);
196             setIcon(flowerImages[index]);
197             if (isSelected) {
198                 setBackground(highlightColor);
199                 setForeground(Color.white);
200             }
201             else {
202                 setBackground(Color.white);
203                 setForeground(Color.black);
204             }
205
206             return this;
207         }
208     }
209 }

Exercises

Problem 1.

In Problem 1 of the previous lecture's exercises, you created the shell of a web browser. Take this code and copy it to a new directory so you can edit it and gradually add browsing functionality to it. It should look something like this:

The browser should have a:

The text component to the right of the "location:" label should be a JTextField. The page area should be a JTextArea. The status bar at the bottom can be made up of a JLabel.

The first functionality to add to the browser is to load and display a text (not HTML) file when the user types a file pathname in the location JTextField. (For the page area, you can use a JTextArea.) Use a FileReader to read the file. (In other words, you'll assume that the file is some kind of character file.) Each time the user types in a file path name on the location text field, the contents of the file, interpreted as characters, should show up in the page area of the browser.

Problem 2.

If the user types in a file path name and hits return, but the file doesn't exist, write "Requested file not found." to the status bar and clear the page area. If any other problem (IO error or otherwise) occurs that prevents the page from being loaded, print "Software Error 2193715; Please call tech support.", or some message of your own invention, on the status bar. If the user types a file path and hits return and you are able to display the page, be sure to clear the status bar so that it never shows stale error messages.

Problem 3.

Allow the user to specify a home page via the "Edit-->Home Page Location" menu selection. When "Home Page Location" is selected, pop up a dialog box that prompts for and accepts a home page file path name. (At this point, don't worry about remembering the home page between invocations of the application. Just be sure to remember the home page while the application is running.)

Problem 4.

When the user presses the "Home" button or selects the "Go-->Home" menu selection, attempt to read and display the home page. If the page isn't readable, do the same behavior as if the user had typed the non-working file path into the location text field: blank the page area and put up an informative message at the status bar.

Problem 5.

Make the forward and back buttons on the toolbar work as expected. When the browser starts, both the back and forward buttons are disabled. As soon as the user types in the second page and the browser successfully loads, the back button should become enabled. When the user presses the back button, the browser returns to the previously viewed page. When the last page in the history is reached, the back button should become disabled. After the first back button press, the forward button should become enabled and stay enabled unless the user presses forward enough times to reach the end of history.

In addition, make the "Go-->Back" menu selection work the same as pressing the back button. Make the "Go-->Forward" menu selection work the same as pressing the go button.

Problem 6.

Assign mnemonics to the buttons:

Problem 7.

Assign mnemonics to the menus and menu items:

Problem 8.

Assign keyboard accelerators to some of the menu items:

Problem 9.

When the user selects the "File-->Open" menu selection, pop up a JFileDialog that lets the user browser the local file system for a file to display. If the user selects a file, attempt to display the file in the usual way. As always, report any errors by clearing the page area and explaining the situation on the status bar.

Problem 10.

When the user presses the Reload button or selects "View-->Reload", read in the currently showing page again.

Note: From this point forward in the browser project, you need to know something about network programming.

Problem 11.

Allow the user to type in either a file path name or a URL into the location text field. If the user types a URL, attempt to load the text file from that URL. Otherwise, interpret the typed string as a file path name, and attempt to load a text file from the local file system as before. (If you instantiate a java.net.URL object, it's constructor will inform you with a MalformedURLException if the typed string isn't really a URL.)

For More Fun:

Allow the user to load in web pages that are actually rendered as web pages in your browser, not just as text files.

Extra Problem.

Using a Swing JApplet, create a Java applet named Scroller that scrolls a banner from right to left. The banner can be optionally specified as a parameter to the applet. The applet's Java code should just use Swing components.

Two buttons, labeled Go and Stop, sit at the base of the applet. When the applet starts, the banner begins scrolling right to left, Go button is disabled and the Stop button is enabled. If the Stop button is pressed, the scrolling animation stops, the Stop button becomes disabled, and the Go button becomes enabled. Pressing the now enabled Go button starts the animation again, disables the Go button and enables the Stop button.

Because this applet is r JApplet, you'll have to run it with appletviewer because neither Netscape Navigator nor Microsoft Internet Explorer support 1.2. (Actually, were you to download the appropriate library from Sun and install it in the right place, you might be able to get Swing to run in these browsers. Swing can run under 1.1, its just not delivered standard with 1.1.)

Input to the Applet

The Scroller applet takes one optional parameter, Banner. Thus, the applet can be embedded in a web page in either of these two ways:

<applet CODE="Scroller.class" WIDTH="300" HEIGHT="150">
<param name="Banner" value="This is the last homework!">
</applet>

or

<applet CODE="Scroller.class" WIDTH="300" HEIGHT="150">
</applet>

If the Banner parameter is missing from the HTML tag, the applet will scroll a default banner of your choice. If the Banner parameter exists, scroll its value.

A minimal HTML page that includes this applet is:

<html>
<head></head>
<body>
<applet CODE="Scroller.class" WIDTH="300" HEIGHT="150">
<param name="Banner" value="Follow your bliss.">
</applet>
</body>
</html>

Given this page in a file named Test.html, you could execute the applet by loading the page into a browser or with appletviewer by typing the command:

appletviewer Test.html

Structure of the Applet

The applet will be made up of two public top-level classes named:

The Scroller class will include anonymous inner classes that define AWT event handlers, so you will get some extra class files generated (with names like Scoller$1.class) when you compile the class. (In addition, if you create a Runner class as an inner class to TextScrollPanel, as I do in EclipseApplet, then you'll end up with a TextScrollPanel$Runner.class when you compile TextScrollPanel.java.)

The Scroller applet (Scroller extends JApplet) uses a BorderLayout to place a panel holding the two buttons at the "South" of the applet and a TextScrollPanel in the "Center". TextScrollPanel (which extends JPanel) has a structure similar to the EclipseApplet from the Applets and AWT Graphics lecture.

Like the EclipseApplet, the TextScrollPanel has start() and stop() methods that start and stop the animation thread. Also like the EclipseApplet, The TextScrollPanel paint() method must use double buffering to avoid flicker. One difference between the paint() methods is where EclipseApplet's paint() method animates a moon, TextScrollPanel's paint() method will animate text.

The Scroller class, which extends java.applet.Applet, must also define start() and stop() methods, because this applet fires off an extra thread to do the animation. Scroller's start() method need only invoke TextScrollPanel's start() method, and Scroller's stop() method need only invoke TextScrollPanel's stop() method. This way, when the browser leaves the page containing your applet and invokes stop(), your applet's animation thread will be killed. If the browser returns to your page and invokes start() again, a new thread will be created that picks up where the old thread left off. This is the way you should write any applet that creates its own threads.

To respond to the button presses, you'll need to add a ButtonListener to each button. Define these as inner classes. The actionPerformed() method of the Go button's listener should:

The actionPerformed() method of the Stop button's listener should:


Sponsored Links

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use