Chapter 15

Responding to Keystrokes and Mouse Clicks

In This Chapter

arrow Creating code to handle mouse clicks (and other such events)

arrow Writing and using a Java interface

In the late 1980s, I bought my first mouse. I paid $100 and, because I didn’t really need a mouse, I checked with my wife before buying it. (At the time, my computer ran a hybrid text/windowed environment. Anything that I could do with a mouse, I could just as easily do with the Alt key.)

Now it’s the 21st century. The last ten mice that I got were free. Ordinary ones just fall into my lap somehow. A few exotic mice were on sale at the local computer superstore. One cost $10 and came with a $10 rebate.

As I write this chapter, I’m using the most recent addition to my collection — an official For Dummies mouse. This yellow and white beauty has a little compartment filled with water. Instead of a snowy Atlantic City scene, the water surrounds a tiny Dummies Man charm. It’s so cute. It was a present from the folks at Wiley Publishing.

Go On … Click That Button

In previous chapters, I create windows that don’t do much. A typical window displays some information but doesn’t have any interactive elements. Well, the time has come to change all that. This chapter’s first example is a window with a button on it. When the user clicks the button, darn it, something happens. The code is shown in Listing 15-1, and the main method that calls the code in Listing 15-1 is in Listing 15-2.

Listing 15-1: A Guessing Game

  import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class GameFrame extends JFrame implements ActionListener {
  private static final long serialVersionUID = 1L;

  int randomNumber = new Random().nextInt(10) + 1;
  int numGuesses = 0;

  JTextField textField = new JTextField(5);
  JButton button = new JButton("Guess");
  JLabel label = new JLabel(numGuesses + " guesses");

  public GameFrame() {
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setLayout(new FlowLayout());
     add(textField);
     add(button);
     add(label);
     button.addActionListener(this);
     pack();
     setVisible(true);
  }

  @Override
  public void actionPerformed(ActionEvent e) {
     String textFieldText = textField.getText();

     if (Integer.parseInt(textFieldText)==randomNumber) {
       button.setEnabled(false);
       textField.setText(textField.getText() + " Yes!");
       textField.setEnabled(false);
     } else {
       textField.setText("");
       textField.requestFocus();
     }

     numGuesses++;
     String guessWord =
        (numGuesses == 1) ? " guess" : " guesses";
     label.setText(numGuesses + guessWord);
  }
}

Listing 15-2: Starting the Guessing Game

  public class ShowGameFrame {
   
  public static void main(String args[]) {
     new GameFrame();
  }
}

Some snapshots from a run of this section’s code are shown in Figures 15-1 and 15-2. In a window, the user plays a guessing game. Behind the scenes, the program chooses a secret number (a number from 1 to 10). Then the program displays a text field and a button. The user types a number in the text field and clicks the button. One of two things happens next:

  • If the number that the user types in isn’t the same as the secret number, the computer posts the number of guesses made so far. The user gets to make another guess.
  • If the number that the user types in is the same as the secret number, the text field displays Yes!. Meanwhile, the game is over, so both the text field and the button become disabled. Both components have that gray, washed-out look, and neither component responds to keystrokes or mouse clicks.
9781118407806-fg1501.tif

Figure 15-1: An incorrect guess.

9781118407806-fg1502.tif

Figure 15-2: The correct guess.

In Listing 15-1, the code to create the frame, the button, and the text field isn’t earth-shattering. I did similar things in Chapters 9 and 10. The JTextField class is new in this chapter, but a text field isn’t much different from a button or a label. Like so many other components, the JTextField class is defined in the javax.swing package. When you create a new JTextField instance, you can specify a number of columns. In Listing 15-1, I create a text field that’s five columns wide.

cross-reference.eps Listing 15-1 uses a fancy operator to decide between the singular guess and the plural guesses. If you’re not familiar with this use of the question mark and colon, see Chapter 11.

Events and event handling

The big news in Listing 15-1, shown in the preceding section, is the handling of the user’s button click. When you’re working in a graphical user interface (GUI), anything the user does (like pressing a key, moving the mouse, clicking the mouse, or whatever) is called an event. The code that responds to the user’s press, movement, or click is called event-handling code.

Listing 15-1 deals with the button-click event with three parts of its code:

  • The top of the GameFrame class declaration says that this class implements ActionListener.
  • The constructor for the GameFrame class adds this to the button’s list of action listeners.
  • The code for the GameFrame class has an actionPerformed method.

Taken together, all three of these tricks make the GameFrame class handle button clicks. To understand how it works, you have to know about something called an interface, which I discuss in the following section.

The Java interface

You may have noticed that, in Java, you never get a class to extend more than one parent class. In other words, you never say

  class DontDoThis extends FirstClass, SecondClass

A class can have only one parent class, and that’s fine when you want your new class to be like a frame. But what if you want your new class to be like a frame and a button-click-listening thing? Can your new class be like both things?

Yes, it can be. Java has this thing called an interface. An interface is like a class, but it’s different. (So, what else is new? A cow is like a planet, but it’s quite a bit different. Cows moo; planets hang in space.) Anyway, when you hear the word interface, you can start by thinking of a class. Then, in your head, note the following things:

  • A class can extend only one parent class, but a class can implement more than one interface.

    For instance, if you want GameFrame to listen for keystrokes as well as button clicks, you can say

      class GameFrame extends JFrame
       implements ActionListener, ItemListener

  • An interface’s methods have no bodies of their own.

    Here’s a copy of the API code for the ActionListener interface:

      package java.awt.event;

    import java.util.EventListener;

    public interface ActionListener
                         extends EventListener {

       public void actionPerformed(ActionEvent e);

    }

    I’ve removed the code’s comments, but I’ve avoided messing with the API code in any significant ways. In this code, the actionPerformed method has no body — no curly braces and no statements to execute. In place of a body, there’s just a semicolon.

    technicalstuff.eps A method with no body, like the method defined in the ActionListener interface, is called an abstract method.

  • When you implement an interface, you provide bodies for all the interface’s methods.

    That’s why an actionPerformed method appears in Listing 15-1. By announcing that it will implement the ActionListener interface, the code in Listing 15-1 agrees that it will give meaning to the interface’s actionPerformed method. In this situation, giving meaning means declaring an actionPerformed method with curly braces, a body, and maybe some statements to execute.

    When you announce that you’re going to implement an interface, the Java compiler takes this announcement seriously. Later on in the code, if you fail to give meaning to any of the interface’s methods, the compiler yells at you.

tip.eps If you’re really lazy, you can quickly find out what methods need to be declared in your interface-implementing code. Try to compile the code, and the compiler lists all the methods that you should have declared but didn’t.

technicalstuff.eps Chapter 8 introduces the use of @Override — a Java annotation. Normally, you use @Override to signal the replacement of a method that’s already been declared in a superclass. But from Java 6 onward, you can also use @Override to signal an interface method’s implementation. That’s what I do in Listing 15-1.

Threads of execution

Here’s a well-kept secret: Java programs are multithreaded, which means that several things are going on at once whenever you run a Java program. Sure, the computer is executing the code that you’ve written, but it’s executing other code as well (code that you didn’t write and don’t see). All this code is being executed at the same time. While the computer executes your main method’s statements, one after another, the computer takes time out, sneaks away briefly, and executes statements from some other, unseen methods. For most simple Java programs, these other methods are ones that are defined as part of the Java Virtual Machine (JVM).

For instance, Java has an event-handling thread. While your code runs, the event-handling thread’s code runs in the background. The event-handling thread’s code listens for mouse clicks and takes appropriate action whenever a user clicks the mouse. Figure 15-3 illustrates how this works.

9781118407806-fg1503.tif

Figure 15-3: Two Java threads.

When the user clicks the button, the event-handling thread says, “Okay, the button was clicked. So, what should I do about that?” And the answer is, “Call some actionPerformed methods.” It’s as if the event-handling thread has code that looks like this:

  if (buttonJustGotClicked()) {
   object1.actionPerformed(infoAboutTheClick);
   object2.actionPerformed(infoAboutTheClick);
   object3.actionPerformed(infoAboutTheClick);
}

Of course, behind every answer is yet another question. In this situation, the follow-up question is, “Where does the event-handling thread find actionPerformed methods to call?” And there’s another question: “What if you don’t want the event-handling thread to call certain actionPerformed methods that are lurking in your code?”

Well, that’s why you call the addActionListener method. In Listing 15-1, the call

  button.addActionListener(this);

tells the event-handling thread, “Put this code’s actionPerformed method on your list of methods to be called. Call this code’s actionPerformed method whenever the button is clicked.”

So, that’s how it works. To have the computer call an actionPerformed method, you register the method with Java’s event-handling thread. You do this registration by calling addActionListener. The addActionListener method belongs to the object whose clicks (and other events) you’re waiting for. In Listing 15-1, you’re waiting for the button object to be clicked, and the addActionListener method belongs to that button object.

The keyword this

In Chapters 9 and 10, the keyword this gives you access to instance variables from the code inside a method. So, what does the this keyword really mean? Well, compare it with the English phrase “state your name.”

  • I, (state your name), do solemnly swear, to uphold the constitution of the Philadelphia Central High School Photography Society… .

The phrase “state your name” is a placeholder. It’s a space in which each person puts his or her own name.

  • I, Bob, do solemnly swear… .
  • I, Fred, do solemnly swear… .

Think of the pledge (“I … do solemnly swear …”) as a piece of code in a Java class. In that piece of code is the placeholder phrase, “state your name.” Whenever an instance of the class (a person) executes the code (that is, takes the pledge), the instance fills in its own name in place of the phrase “state your name.”

The this keyword works the same way. It sits inside the code that defines the GameFrame class. Whenever an instance of GameFrame is constructed, the instance calls addActionListener(this). In that call, the this keyword stands for the instance itself.

  button.addActionListener(thisGameFrameInstance);

By calling button.addActionListener(this), the GameFrame instance is saying, “Add my actionPerformed method to the list of methods that are called whenever the button is clicked.” And indeed, the GameFrame instance has an actionPerformed method. The GameFrame has to have an actionPerformed method because the GameFrame class implements the ActionListener interface. It’s funny how that all fits together.

Inside the actionPerformed method

The actionPerformed method in Listing 15-1 uses a bunch of tricks from the Java API. Here’s a brief list of those tricks:

  • Every instance of JTextField (and of JLabel) has its own getter and setter methods, including getText and setText. Calling getText fetches whatever string of characters is in the component. Calling setText changes the characters that are in the component. In Listing 15-1, judicious use of getText and setText pulls a number out of the text field and replaces the number with either nothing (the empty string "") or the number, followed by the word Yes!
  • Every component in the javax.swing package (JTextField, JButton, or whatever) has a setEnabled method. When you call setEnabled(false), the component gets that limp, gray, washed-out look and can no longer receive button clicks or keystrokes.
  • Every component in the javax.swing package has a requestFocus method. When you call requestFocus, the component gets the privilege of receiving the user’s next input. For example, in Listing 15-1, the call textField.requestFocus() says “even though the user may have just clicked the button, put a cursor in the text field. That way, the user can type another guess in the text field without clicking the text field first.”

tip.eps You can perform a test to make sure that the object referred to by the button variable is really the thing that was clicked. Just write if (e.getSource() == 
button). If your code has two buttons, button1 and button2, you can test to find out which button was clicked. You can write if (e.getSource() == button1) and if (e.getSource() == button2).

The serialVersionUID

Chapter 9 introduces the SuppressWarnings annotation to avoid dealing with something called a serialVersionUID. A serialVersionUID is a number that helps Java avoid version conflicts when you send an object from one place to another. For example, you can send the state of your JFrame object to another computer’s screen. Then the other computer can check the frame's version number to make sure that no funny business is taking place.

In Chapter 9, I side-step the serialVersionUID issue by telling Java to ignore any warnings about missing serial version numbers. But in Listing 15-1, I take a bolder approach. I give my JFrame object a real serialVersionUID. This is my first version of GameFrame, so I give this GameFrame the version number 1. (Actually, I give this GameFrame the number 1L, meaning the long value 1. See Chapter 4.)

So when would you bother to change a class’s serialVersionUID number? If version number 1 is nice, is version number 2 even better? The answer is complicated, but the bottom line is, don’t change the serialVersionUID number unless you make incompatible changes to the class’s code. By “incompatible changes,” I mean changes that make it impossible for the receiving computer’s existing code to handle your newly created objects.

cross-reference.eps For more details about the serialVersionUID and what constitutes an incompatible code change, check out this site:

  http://download.oracle.com/javase/7/docs/platform/serialization/spec/version.html#6678

Java has some visual tools to help you design a GUI interface. If you visit www.eclipse.org/windowbuilder, you can read about WindowBuilder for Eclipse. With WindowBuilder, you drag components from a palette onto a frame. (The components include buttons, text fields, and other goodies.) Using your mouse, you can move and resize each component. As you design the frame visually, Eclipse creates the frame’s code automatically. Each component on the frame has a little spreadsheet showing the component’s properties. For example, you can change the text on a button’s face by changing the text entry in the button’s spreadsheet. When you right-click or control-click the picture of a component, you get the option of jumping to the component’s actionPerformed method. In the actionPerformed method, you add Java code, such as button.setText("You clicked me!"). A tool like WindowBuilder makes the design of GUI interfaces quicker, more natural, and more intuitive.

technicalstuff.eps This chapter describes features of Java’s Swing framework. Since 1998, Swing has been Java’s primary framework for developing GUI applications. But late in 2011, Oracle added a newer framework — JavaFX — to Java’s core. JavaFX provides a richer set of components than Swing. But for simple applications, JavaFX is more difficult to use. If you’re interested in reading more about JavaFX, visit this book’s website (www.allmycode.com/JavaForDummies). At the website, you can download GUI versions of many examples in this book. Some of the downloadable GUI versions use JavaFX.

Responding to Things Other Than Button Clicks

When you know how to respond to one kind of event, responding to other kinds of events is easy. Listings 15-3 and 15-4 display a window that converts between U.S. and U.K. currencies. The code in these listings responds to many kinds of events. Figures 15-4, 15-5, and 15-6 show some pictures of the code in action.

Listing 15-3: Displaying the Local Currency

  import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.NumberFormat;
import java.util.Locale;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class MoneyFrame extends JFrame implements
           KeyListener, ItemListener, MouseListener {
   private static final long serialVersionUID = 1L;
   
   JLabel fromCurrencyLabel = new JLabel(" ");
   JTextField textField = new JTextField(5);
   JLabel label = new JLabel("        ");
   JComboBox<String> combo = new JComboBox<String>();

   NumberFormat currencyUS =
      NumberFormat.getCurrencyInstance();
   NumberFormat currencyUK =
      NumberFormat.getCurrencyInstance(Locale.UK);

   public MoneyFrame() {
      setLayout(new FlowLayout());

      add(fromCurrencyLabel);
      add(textField);
      combo.addItem("US to UK");
      combo.addItem("UK to US");
      add(label);
      add(combo);

      textField.addKeyListener(this);
      combo.addItemListener(this);
      label.addMouseListener(this);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      setSize(300, 100);
      setVisible(true);
   }

   void setTextOnLabel() {
      String amountString = "";
      String fromCurrency = "";
      
      try {
         double amount =
            Double.parseDouble(textField.getText());

         if(combo.getSelectedItem().equals("US to UK"))
         {
            amountString = " = " +
                 currencyUK.format(amount * 0.61214);
            fromCurrency = "$";
         }
         if(combo.getSelectedItem().equals("UK to US"))
         {
            amountString = " = " +
                 currencyUS.format(amount * 1.63361);
            fromCurrency = "u00A3";
         }
         
      } catch (NumberFormatException e) {
      }

      label.setText(amountString);
      fromCurrencyLabel.setText(fromCurrency);
   }
   
   @Override
   public void keyReleased(KeyEvent k) {
      setTextOnLabel();
   }
   
   @Override
   public void keyPressed(KeyEvent k) {
   }

   @Override
   public void keyTyped(KeyEvent k) {
   }
   
   @Override
   public void itemStateChanged(ItemEvent i) {
      setTextOnLabel();
   }

   @Override
   public void mouseEntered(MouseEvent m) {
      label.setForeground(Color.red);
   }

   @Override
   public void mouseExited(MouseEvent m) {
      label.setForeground(Color.black);
   }

   @Override
   public void mouseClicked(MouseEvent m) {
   }

   @Override
   public void mousePressed(MouseEvent m) {
   }

   @Override
   public void mouseReleased(MouseEvent m) {
   }
}

Listing 15-4: Calling the Code in Listing 15-3

  public class ShowMoneyFrame {
   
   public static void main(String args[]) {
      new MoneyFrame();
   }
}

9781118407806-fg1504.tif

Figure 15-4: U.S. to U.K. currency.

9781118407806-fg1505.tif

Figure 15-5: Using the combo box.

9781118407806-fg1506.tif

Figure 15-6: U.K. to U.S. currency.

Okay, so Listing 15-3 is a little long. Even so, the outline of the code in Listing 15-3 isn’t too bad. Here’s what the outline looks like:

  class MoneyFrame extends JFrame implements
           KeyListener, ItemListener, MouseListener {

   variable declarations

   constructor for the MoneyFrame class

   declaration of a method named setTextOnLabel

   all the methods that are required because the class
      implements three interfaces
}

The constructor in Listing 15-3 adds the following four components to the new MoneyFrame window:

  • A label: In Figure 15-4, the label displays a dollar sign.
  • A text field: In Figure 15-4, the user types 54 in the text field.
  • Another label: In Figure 15-4, the label displays £33.06.
  • A combo box: In Figure 15-4, the combo box displays US to UK. In Figure 15-5, the user selects an item in the box. In Figure 15-6, the selected item is UK to US.

technicalstuff.eps In Java, a JComboBox (commonly called a drop-down list) can display items of any kind. In Listing 15-3, the generic new JComboBox<String>() code constructs a JComboBox whose entries have type String. That seems sensible, but if your application has a Person class, you can construct new JComboBox<Person>(). In that situation, Java has to know how to display each Person object in the drop-down list. (It isn’t a big deal. Java finds out how to display a person by looking for a toString() method inside the Person class.)

The MoneyFrame implements three interfaces — the KeyListener, ItemListener, and MouseListener interfaces. Because it implements three interfaces, the code can listen for three kinds of events. I discuss the interfaces and events in the following list:

  • KeyListener: A class that implements the KeyListener interface must have three methods named keyReleased, keyPressed, and keyTyped. When you lift your finger off a key, the event-handling thread calls keyReleased.

    In Listing 15-3, the keyReleased method calls setTextOnLabel. My setTextOnLabel method checks to see what’s currently selected in the combo box. If the user selects the US to UK option, the setTextOnLabel method converts dollars to pounds. If the user selects the UK to US option, the setTextOnLabel method converts pounds to dollars.

    technicalstuff.eps In the setTextOnLabel method, I use the string "u00A3". The funny-looking u00A3 code is Java’s UK pound sign. (The u in u00A3 stands for Unicode — an international standard for representing characters in the world's alphabets.) If my operating system’s settings defaulted to UK currency, in the runs of Java programs, the pound sign would appear on its own. For information about all this, check out the Locale class in Java’s API documentation.

    By the way, if you’re thinking in terms of real currency conversion, forget about it. This program uses rates that may or may not have been accurate at one time. Sure, a program can reach out on the Internet for the most up-to-date currency rates, but at the moment, you have other Javafish to fry.

  • ItemListener: A class that implements the ItemListener interface must have an itemStateChanged method. When you select an item in a combo box, the event-handling thread calls itemStateChanged.

    In Listing 15-3, when the user selects US to UK or UK to US in the combo box, the event-handling thread calls the itemStateChanged method. In turn, the itemStateChanged method calls setTextOnLabel, and so on.

  • MouseListener: A class that implements the MouseListener interface must have mouseEntered, mouseExited, mouseClicked, mousePressed, and mouseReleased methods. Implementing MouseListener is different from implementing ActionListener. When you implement ActionListener, as in Listing 15-1, the event-handling thread responds only to mouse clicks. But with MouseListener, the thread responds to the user pressing the mouse, releasing the mouse, and more.

    In Listing 15-3, the mouseEntered and mouseExited methods are called whenever you move over or away from the label. How do you know that the label is involved? Just look at the code in the MoneyFrame constructor. The label variable’s addMouseListener method is the one that’s called.

    Look at the mouseEntered and mouseExited methods in Listing 15-3. When mouseEntered or mouseExited is called, the computer forges ahead and calls setForeground. This setForeground method changes the color of the label’s text.

    Isn’t modern life wonderful? The Java API even has a Color class with names like Color.red and Color.black.

Listing 15-3 has several methods that aren’t really used. For instance, when you implement MouseListener, your code has to have its own mouseReleased method. You need the mouseReleased method not because you’re going to do anything special when the user releases the mouse button, but because you made a promise to the Java compiler and have to keep that promise.

Creating Inner Classes

Here’s big news! You can define a class inside of another class! For the user, Listing 15-5 behaves the same way as Listing 15-1. But in Listing 15-5, the GameFrame class contains a class named MyActionListener.

Listing 15-5: A Class within a Class

  import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class GameFrame extends JFrame {
  private static final long serialVersionUID = 1L;

  int randomNumber = new Random().nextInt(10) + 1;
  int numGuesses = 0;

  JTextField textField = new JTextField(5);
  JButton button = new JButton("Guess");
  JLabel label = new JLabel(numGuesses + " guesses");

  public GameFrame() {
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setLayout(new FlowLayout());
     add(textField);
     add(button);
     add(label);
     button.addActionListener(new MyActionListener());
     pack();
     setVisible(true);
  }

  class MyActionListener implements ActionListener {

     @Override
     public void actionPerformed(ActionEvent e) {
       String textFieldText = textField.getText();

       if (Integer.parseInt
             (textFieldText) == randomNumber) {
         button.setEnabled(false);
         textField.setText
             (textField.getText() + " Yes!");
         textField.setEnabled(false);
       } else {
         textField.setText("");
         textField.requestFocus();
       }

       numGuesses++;
       String guessWord =
          (numGuesses == 1) ? " guess" : " guesses";
       label.setText(numGuesses + guessWord);
     }
  }
}

The MyActionListener class in Listing 15-5 is an inner class. An inner class is a lot like any other class. But within an inner class’s code, you can refer to the enclosing class’s fields. For example, several statements inside MyActionListener use the name textField, and textField is defined in the enclosing GameFrame class.

Notice that the code in Listing 15-5 uses the MyActionListener class only once. (The only use is in a call to button.addActionListener.) So I ask, do you really need a name for something that’s used only once? No, you don’t. You can substitute the entire definition of the inner class inside the call to button.addActionListener. When you do this, you have an anonymous inner class. Listing 15-6 shows you how it works.

Listing 15-6: A Class with No Name (Inside a Class with a Name)

  import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class GameFrame extends JFrame {
  private static final long serialVersionUID = 1L;

  int randomNumber = new Random().nextInt(10) + 1;
  int numGuesses = 0;

  JTextField textField = new JTextField(5);
  JButton button = new JButton("Guess");
  JLabel label = new JLabel(numGuesses + " guesses");

  public GameFrame() {
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setLayout(new FlowLayout());
     add(textField);
     add(button);
     add(label);
     button.addActionListener(new ActionListener() {
       
       @Override
       public void actionPerformed(ActionEvent e) {
         String textFieldText = textField.getText();

         if (Integer.parseInt
               (textFieldText) == randomNumber) {
           button.setEnabled(false);
           textField.setText
               (textField.getText() + " Yes!");
           textField.setEnabled(false);
         } else {
           textField.setText("");
           textField.requestFocus();
         }

         numGuesses++;
         String guessWord =
            (numGuesses == 1) ? " guess" : " guesses";
         label.setText(numGuesses + guessWord);
       }
     });
     pack();
     setVisible(true);
  }
}

Inner classes are good for things like event handlers, such as the action
Performed method in this chapter’s examples. The most difficult thing about an anonymous inner class is keeping track of the parentheses, the curly braces, and the indentation. So my humble advice is, start by writing code without any inner classes, as in the code from Listing 15-1. Later, when you become bored with ordinary Java classes, experiment by changing some of your ordinary classes into inner classes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.151.220