Chapter 21. JFC and the Swing Package

JFC and the Swing Package

In Chapter 19, we saw that the basic idea behind Java GUI programs is that you:

  • Declare controls. You can subclass them to add to the behavior, but this is often unnecessary.

  • Implement an interface to get the event-handler that responds to control activity.

  • Add the controls to a container. Again, subclassing is possible but frequently unnecessary.

That chapter explained how to handle the events that controls generate. This chapter dives into the details of the controls themselves: what they look like, how you use them, and what they do. The next chapter wraps up by describing containers and how you use them to lay out controls neatly on the screen.

Java Foundation Classes

Supporting a Java interface to the underlying native window libraries achieves the goal of making Java GUI programs highly portable, but it comes at the cost of inefficiency. Peer events must be translated into Java events before they can be handled by Java code. Worse, native libraries aren’t identical on each platform, and sometimes the differences leak into the Java layer.

The Java Foundation Classes (JFC) are a set of GUI-related classes created to solve the AWT problem of platform idiosyncrasies. JFC also supports:

  • A pluggable look-and-feel, meaning that when you run the program, you can choose whether you want it to look like a Windows GUI, a Macintosh GUI, or some other style.

  • An accessibility API for things like larger text for the visually impaired.

  • The Java 2D drawing API.

  • A drag-and-drop library and an “undo last command” library.

  • The Swing component set.

The Swing components (scrollbar, button, textfield, label, etc.) replace the AWT versions of these components. The AWT is still used for the other areas of GUI functionality, like layout control and printing. There’s an appendix in this book that contains descriptions of the AWT components. They are simpler than the Swing components, but more basic and more bug-prone. We’re describing and working with JFC from here on.

JFC is bundled with JDK 1.2 as a standard part of Java and was also available unbundled for JDK 1.1. Although it’s a core library now, the “x” in the package name in JDK 1.2, javax.swing, reflects the fact that the package first became available as an optional extension library. There was quite a bit of churn over the correct package name for Swing, and the unbundled version for JDK 1.1 was released as package com.sun.java.swing. You should use Swing, rather than AWT components, in new programs you write. All browsers now support Swing through the use of the plug-in.

The Java Foundation Classes are aimed squarely at programmers who want to build enterprise-ready software at least as good as (often better than) software built with native GUI libraries. The JFC has the additional advantage of being a lot simpler than competing window systems and producing code that runs on all systems. It is also future-proof. Your programs won’t stop working on your next OS change. JFC is the most important thing to happen in user interfaces since the Macintosh operating system.

Some Terminology

In Win32, the term control means the group of all the GUI things that users can press, scroll, choose between, type into, draw on, and so forth. In the Unix XWindows world, a control is called a widget.

Neither control nor widget is a Java term. Instead, we use the term Component, or, when talking specifically about Swing, the JComponent subclass of Component. Each Swing control is a subclass of javax.swing.JComponent, so each control inherits all the methods and data fields of JComponent. JComponents are serializable, meaning the object can be written out to disk, can be read in again later, and can become an object again. They follow the rules for JavaBeans, so they can be coupled together in visual builder tools.

This whole chapter is about explaining the Swing components and how you use them. You will build up your GUI programs using these components. The first thing to note is that the Swing components are no longer peer-based, but are written in Java and are thus consistent on all platforms. Under the AWT, a button ended up being a Win32 button on Windows, a Macintosh button on the Macintosh, and a Motif button on Unix. With Swing, the button is rendered on a little bit of screen area that belongs to some ancestor Java component, and Swing puts all the button semantics on top of that. Swing draws the button so it looks armed (ready to push), pushed, or disabled. Because the code is written in Java, the button has identical behavior no matter where it runs.

Frankly, JFC is a very big topic. There are more than three hundred classes in the Swing library alone. We’ll present nine or ten individual Swing JComponents here, and provide pointers on the rest. This amounts to quite a few pages, so I recommend you read one or two in depth, then just look at the figures to get an idea of what each does. Return to the appropriate section in the chapter as you need actual code examples.

Overview of JComponent

Object-oriented programming fits well with window systems. The concept of making new controls by subclassing existing ones and overriding part of their behavior saves time and effort. Another similarity is the way that controls have to handle events just as objects handle messages. Method calls are equivalent to sending a message to an object, and some OOP languages even refer to a method call as “sending a message.”

There is an abstract class called JComponent, which is the parent class for most things that can appear on screen. The basic ingredients of a GUI are all subclasses of the class called JComponent. JComponent is the superclass that holds the common information about an on-screen control and provides higher-level features common to each control, such as:

  • Size (preferred, minimum, and maximum).

  • Double buffering (a technique to make frequently changing components look smoother with less flickering).

  • Support for accessibility and internationalization.

  • Tooltips (pop-up help when you linger on a JComponent).

  • Support for operating the control with the keyboard instead of the mouse.

  • Some help for debugging by slowing component rendering so you can see what’s happening.

  • The thickness of any lines or insets around the edge of the Control.

Components correspond to “things that interact with the user” and Containers are “backdrops to put them on.” The superclass of javax.swing.JComponent is java.awt.Container. And the parent of Container is java.awt.Component.

The behavior and appearance of each specific control is one level down in the subclasses of JComponent. The Swing lightweight controls can be divided up as shown in Table 21-1. We will look at just one or two components from each of these categories.

Each control has methods appropriate to what it does. The JFileChooser control has methods to get and set the current directory, get the selected filename(s), apply a filename filter, and so on. We’ll examine these individual JComponents later in the chapter.

Table 21-1. Swing Lightweight Controls

GUI Category

Control Swing

Class Name

Basic Controls

Button

Combo box

List

Menu

Slider

Toolbar

Text fields

JButton, JCheckBox,

JRadioButton

JComboBox

JList

JMenu, JMenuBar, JMenuItem

JSlider

JToolbar

JTextField, JPasswordField,

JTextArea, JFormattedTextField

Uneditable Displays

Label

Tooltip

Progress bar

JLabel

JToolTip

JProgressBar

Editable Displays

Table

Text

Tree

Color chooser

File chooser

Value chooser

JTable

JTextPane,

JTextArea,JEditorPane

JTree

JColorChooser

JFileChooser

JSpinner

Space-Saving Containers

Scroll pane

Split pane

Tabbed pane

JScrollPane, JScrollBar

JSplitPane

JTabbedPane

Top-Level Containers

Frame

Applet

Dialog

JFrame

JApplet

JDialog, JOptionPane

Other Containers

Panel

Internal frame

Layered pane

Root pane

JPanel

JInternalFrame

JLayeredPane

JRootPane

All About Controls (JComponents)

We now have enough knowledge to start looking at individual controls in detail and to describe the kinds of events they can generate. Almost the whole of window programming is learning about the different controls that you can put on the screen and how to drive them. This section (at last) describes some individual controls. The controls shown in Figure 21-1 are all subclasses of the general class JComponent that we have already seen.

Some JComponent controls (visible GUI objects) of Java.

Figure 21-1. Some JComponent controls (visible GUI objects) of Java.

These classes are the controls or building blocks from which you create your GUI. What you do with all these components is the following:

Some JComponent controls (visible GUI objects) of Java.
  1. Add them to the content pane of a container (often JFrame or JApplet) with a call like:

    MyJContainer.getContentPane().add( myJComponent ); 

    The content pane is a layer within a container whose purpose is to have controls added to it. This is not well thought out. It would be better if you just added controls to a container, as you do in the AWT. Sun actually added a special check for this at runtime. If you add to a container instead of a container’s content pane, it throws an exception and the message reminds you of the “right” way to do it!

  2. Register your event-handler using the addSomeListener() method of the control. This tells the window system which routine of yours should be called when the user presses buttons or otherwise makes selections to process the event.

Fortunately, both of these activities are quite straightforward, and we’ll cover them here in source code, words, and pictures. The add method can be applied to a Frame in an application like this:

JFrame jf = new JFrame();
                  ...
jf.getContentPane().add( something ); 

Or, it can be applied to the JApplet ’s panel like so:

public static void init () {
        this.getContentPane().add( something ); 

Recall the Applet/JApplet life cycle described in an earlier chapter. That discussion made clear that there is an init() method which each Applet should override. It will be called when the applet is loaded, and it is a good place to place the code that creates these GUI objects. We will use init() for that purpose. If you are writing an applet with Swing components, you must use JApplet (not Applet) as your parent class to ensure that all drawing and updates take place correctly.

Whenever a user operates a JComponent (presses a button, clicks on a choice), an event is generated. The source code for the event class can be seen in the $JAVAHOME/src/java/awt/event directory. It contains information about the coordinates of the event, the time it occurred, and the kind of event that it was. If the event was a key press, it has the value of the key. If the event was a selection from a list, it has the string chosen.

As we saw in the previous chapter, the runtime library creates one of these event objects for each occurrence of an event and queues them up on the event queue. The event dispatching thread takes event objects off the queue and calls your appropriate event handlers with the event object as an argument.

How to Display Components

Containers are the objects that are displayed directly on the screen. Controls must be added to a Container if you want to see them. The container in this example driver program is called JFrame. JFrame will be the main window for most of your Swing applications.

Let’s create a JFrame, set its size, set it visible, tell it how to arrange JComponents that are added, and add some event-handler code to exit the program when it detects that you have clicked on the JFrame to close it. Phew! That’s quite a list of tasks, so we’ll split them off into a separate method. Make everything static. In this way, we can use it from the main() method, and we get the following:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Demo {
         static JFrame jframe = new JFrame(“Example”);

         public static void setupJFrame() {
                  jframe.setSize(400,100);
                  jframe.setVisible(true);
                  jframe.getContentPane().setLayout( new FlowLayout() );

                 WindowListener l = new WindowAdapter() {
                             public void windowClosing(WindowEvent e) {
                                      System.exit(0);}
                  };
                   jframe.addWindowListener(l);
        }

        public static void main(String[] args) {
                  setupJFrame();
                  JButton jb = new JButton("pressure");
                  jframe.getContentPane().add( jb );
                  jframe.setVisible(true);
      }
} 

The JButton Component that we are trying to demonstrate is printed in bold type. The line that follows adds the JComponent to the JFrame’s content pane. To cut down on the extraneous code in the pages ahead, I’ll show only the statements that directly deal with the JComponent. That means I’ll show only the two bold statements in the example above. You should supply all the missing code when you compile and run the examples. Next, a thread caution, then on to the first example!

Swing Threads—A Caution!

Here’s a caution relating to threads. The GUI components are maintained on the screen by a thread of their own, separate to any threads that you have running in your code. This GUI thread is called the event-dispatching thread, and it takes care of rendering the GUI components and processing any GUI events that take place. An example of a GUI event would be a mouse click, a selection from a menu, or a keystroke on a text field.

The need for thread safety occurs in the system libraries just as much as it does in your code. To work properly, Swing requires that all code that might affect GUI components be executed from the event-dispatching thread!

As you know, events are handled by a callback from the window system to an event handler object you supply. That means that your event-handler code automatically executes in the event-dispatching thread, as it should. But should you try to create new GUI components in some other thread of yours, your thread will not be synchronized with runtime library data structures. Thus, the only place where you should create, modify, set visible, set size, or otherwise adjust GUI components, is in your event handler code. Otherwise, you will bring hard-to-debug synchronization problems down on your own head.

Here is an example of the natural-looking code which is erroneous:

public static void main (String[] args) {
        createSomeFrame(); // created in the main thread
        showThatFrame();   // shown by main thread,
        // now that first component is displayed, no more
        // code that affects components may be run from
        // any thread other than the event-dispatching thread
        createSomeOtherGUIComponent(); // WRONG!!!
} 

There is one exception to the rule of doing GUI work only in the eventdispatching thread, which fortunately allows us to write our programs in the most natural way. You are allowed to construct a GUI in the application’s main method or the Applet’s init method, providing no GUI components are already on the screen from your program and providing you do not further adjust it from this thread after the GUI becomes visible. Most people obey these rules by accident, but you should know about them. For practical purposes, this means if you want to create a new GUI component in response to a GUI event, you must do the instantiation in the code that handles the GUI event.

If you have to do some further GUI work from one of your own threads, you can easily put it into the correct thread by using the Runnable interface. There is a Swing utility that takes a Runnable as an argument and runs it in the event dispatching thread. The code is as follows:

Runnable toDo= new Runnable() {
     public void run() {
          // things to do in the event-dispatching thread
          doTheWork();
     }
};
          ...
     SwingUtilities.invokeLater( toDo ); 

Be careful to follow this protocol in Swing programs! Now let’s look at some Swing components.

Swing Components

JLabel

What it is: JLabel is the simplest JComponent. It is just a string, image, or both that appears on screen. The contents can be left-, right-, or center-aligned according to an argument to the constructor. The default is left-aligned. JLabel is a cheap, fast way to get a picture or text on the screen

What it looks like on-screen:

JLabel

The code to create it:

//  remember, we are only showing relevant statements from main()
     ImageIcon icon = new ImageIcon("star.gif");
     JLabel jl = new JLabel("You are a star", icon, JLabel.CENTER);

     frame.getContentPane().add( jl );
     frame.pack(); // size the JFrame to fit its contents 

Note the way we can bring in an image from a GIF or JPEG file by constructing an ImageIcon with a pathname to a file. Labels do not generate any events in and of themselves. It is possible, however, to get and set the text of a label. You might do that in response to an event from a different component. The constructors for JLabel are:

public javax.swing.JLabel(java.lang.String);
public javax.swing.JLabel(java.lang.String,int);
public javax.swing.JLabel(java.lang.String,javax.swing.Icon,int);
public javax.swing.JLabel(javax.swing.Icon);
public javax.swing.JLabel(javax.swing.Icon,int); 

The int parameter is a constant from the JLabel class specifying left-, right- or center-alignment in the area where the label is displayed.

JLabels are typically used to augment other controls with descriptions or instructions. People often want to know how to get a multiline label (or a multiline button). There is no direct way. Either use multiple labels, or program the functionality in for yourself by extending the class JComponent to do what you want.

JButton

What it is: This is a GUI button. You supply code for the action that is to take place when the button is pressed.

What it looks like on-screen:

JButton

The code to create it:

JButton jb = new JButton("pressure");
jframe.getContentPane().add( jb ); 

The code to handle events from it:

jb.addActionListener( new ActionListener() {
     int i = 1;
     public void actionPerformed(ActionEvent e)
          { System.out.println("pressed "+ i++); }
     } ); 

When you press this button, the event-handler will print out the number of times it has been pressed. You can easily create buttons with images as well, like this:

Icon spIcon = new ImageIcon("spam.jpg");
JButton jb = new JButton("press here for Spam", spIcon); 
JButton

JButton

You can add a keyboard accelerator to a button, and you can give it a symbolic name for the text string that it displays. This helps with internationalizing code.

Program an “Alice in Wonderland” JFrame with two buttons, one of which makes the frame grow larger, the other smaller. The Component method setSize(int, int) will resize a component. (Easy—about twenty lines of code).

JToolTip

What it is: This is a text string that acts as a hint or further explanation. You can set it for any JComponent. It appears automatically when the mouse lingers on that component and it disappears when you roll the mouse away.

Tooltips don’t generate any events so there is nothing to handle.

What it looks like on-screen: We’ll add a tooltip to the JLabel that we showed on the previous page.

JToolTip

The code to create it:

JLabel jl = ...
jl.setToolTipText(“You must practice to be a star!”); 

Notice that you don’t directly create a JToolTip object. That is done for you behind the scenes. You invoke the setToolTipText() method of JComponent.

It’s so quick and easy to create tooltips; use them generously.

JTextField

What it is: This is an area of the screen where you can enter a line of text. There are a couple of subclasses: JTextArea (several lines in size) and JPasswordField (which doesn’t echo what you type in). You can display some initial text. The text is selectable (you can highlight it with the cursor) and can be set to be editable or not editable.

What it looks like on-screen:

JTextField

The code to create it:

JLabel jl = new JLabel("Enter your name:");
JTextField jtf = new JTextField(25); // field is 25 chars wide 

The code to retrieve user input from it: Text fields generate key events on each keystroke and an ActionEvent when the user presses a carriage return. This makes it convenient to validate individual keystrokes as they are typed (as in ensuring that a field is wholly numeric) and to retrieve all the text when the user has finished typing. The code to get the text looks like this:

jtf.addActionListener( new ActionListener() {
     public void actionPerformed(ActionEvent e)
     {  System.out.println(
          " you entered: " + e.getActionCommand() ); }
     } );

Container c = jframe.getContentPane();
c.add( jl );
c.add( jtf ); 

In this example, running the program, typing in a name, and hitting carriage return will cause the name to be echoed on system.out. You should write some code to try implementing a listener for each keystroke.

JCheckBox

What it is: A checkbox screen object that represents a boolean choice: pressed, not pressed, on, or off. Usually some text explains the choice. For example, a “Press for fries” JLabel would have a JCheckBox “button” allowing yes or no. You can also add an icon to the JCheckBox, just the way you can with JButton.

What it looks like on-screen:

JCheckBox

The code to create it:

JCheckBox jck1 = new JCheckBox("Pepperoni");
JCheckBox jck2 = new JCheckBox("Mushroom");
JCheckBox jck3 = new JCheckBox("Black olives");
JCheckBox jck4 = new JCheckBox("Tomato");
Container c = jframe.getContentPane();
c.add( jck1 ); c.add( jck2 ); // etc... 

The code to retrieve user input from it: Checkbox generates both ActionEvent and ItemEvent every time you change it. This seems to be for backward compatibility with AWT. We already saw the code to handle ActionEvents with Button. The code to register an ItemListener looks like this:

jck2.addItemListener( new ItemListener()
{ // anonymous class
        public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange()==e.SELECTED)
                      System.out.print("selected ");
                else System.out.print("de-selected ");
                System.out.print("Mushroom
");
        }
} ); 

In this example, running the program and clicking the “Mushroom” checkbox will cause the output of selected Mushroom in the system console.

Handlers in real programs will do more useful actions as necessary like assigning values and creating objects. The ItemEvent contains fields and methods that specify which object generated the event and whether it was selected or deselected.

JPanel

What it is: There was (and is) an AWT component known as Canvas. It is a screen area that you can use for drawing graphics or receiving user input. A Canvas is usually subclassed to add the behavior you need, especially when you use it to display a GIF or JPEG image. A Canvas contains almost no methods. All its functionality is either inherited from Component (setting font, color, size) or from functionality you add when you extend the class.

Everyone expects there to be a JCanvas replacing Canvas, just as JButton replaces Button, JFrame replaces Frame, and so on. There is no JCanvas. The AWT component Canvas was just like the AWT component Panel, except Panel was also a container. The Swing version of Panel, JPanel, does double duty. It replaces both Canvas and Panel.

To draw on a JPanel, you may want to supply your own version of the method paintComponent(Graphics g). To do that, you need to extend the class and override the paintComponent() method [1] for this Container. That gives you a Graphics context—the argument to paintComponent() —which is used in all drawing operations. The many methods of Graphics let you render (the fancy graphics word for “draw”) lines, shapes, text, etc., on the screen.

A simpler alternative for simpler drawings is to use JLabel to create the picture and add it to JPanel as shown in the following code.

The code to create it: Figure 21-2 results from running the following code:

JPanel replaces Panel and Canvas.

I like this picture because it looks the same in black and white as it does in color.

Figure 21-2. JPanel replaces Panel and Canvas.

class MyJPanel extends JPanel {
     JLabel jl = new JLabel(new ImageIcon( "bmw.jpg"));
     { add(jl); // instance initializer just for fun

          addKeyListener( new KeyAdapter() {
               public void keyPressed(KeyEvent e) {
                    char c = e.getKeyChar();
                    System.out.println("got char "+c);
               }
          } );
    }
}

...

     public static void main(String[] args) {
          setupFrame();
          MyJPanel mjp = new MyJPanel();
          jframe.getContentPane().add(mjp);
          jframe.setVisible(true);
          mjp.requestFocus();
    } 

I have also added a KeyListener for the JPanel here. That allows you to make keystrokes on top of the JPanel and have the callback take place for each one individually. All you do is echo the characters to prove you got them. With the picture backdrop and the capture of individual keystrokes, you have the basics of a computer game right there. There are a couple of real computer games on the CD.

You have to request the focus for a component before key events will be sent to it, and the component has to be visible at the time you do that.

JRadioButton and ButtonGroup

What it is: JRadioButtons are used when you have a group of checkboxes and you want a maximum of one of them to be selected. This was done with a CheckboxGroup in the AWT, but the design has been cleaned and simplified in Swing. JRadioButton, JCheckBox, and JButton are now subclasses of AbstractButton and have common consistent behavior, can be given images, can be embedded in menus, and so on.

The term “radio buttons” arises from the old manual station selection buttons in car radios. When you pressed in one of the buttons, all the others would pop out and be deselected. ButtonGroups work the same way.

What it looks like on-screen:

JRadioButton and ButtonGroup

On Windows, mutually exclusive checkboxes are round, while multiple selection checkboxes are square. This is one of those “look and feel” differences between window systems.

The code to create it: This example shows some more sophisticated things you can do in your event-handler. In this example, we have a JLabel with a picture of the choice. In the event-handler, we set the label to correspond to the RadioButton choice.

The ButtonGroup class automatically takes care of arming the previous radio button when you press another.

// JRadioButton code
     final JLabel piclabel
          = new JLabel(new ImageIcon( pieString + ".gif"));

     /** Listens to the radio buttons. */
     class RadioListener implements ActionListener {
          public void actionPerformed(ActionEvent e) {
          // getting the event causes update on Jlabel icon
          piclabel.setIcon(
               new ImageIcon( e.getActionCommand()+".gif"));
          }
     }

     JRadioButton pieButton = new JRadioButton(pieString);
     pieButton.setMnemonic(’b’);
     pieButton.setActionCommand(pieString);
     pieButton.setSelected(true);

     JRadioButton cakeButton = new JRadioButton(cakeString);
     JRadioButton iceButton = new JRadioButton(iceString);

     // Group the radio buttons.
     ButtonGroup group = new ButtonGroup();
     group.add(pieButton);
     group.add(cakeButton);
     group.add(iceButton);

     // Register a listener for the radio buttons.
     RadioListener myListener = new RadioListener();
     pieButton.addActionListener(myListener);
     cakeButton.addActionListener(myListener);
     iceButton.addActionListener(myListener);

     // Put the radio buttons in a column in a panel to line up
     JPanel radioPanel = new JPanel();
     radioPanel.setLayout(new GridLayout(0, 1));
     radioPanel.add(pieButton);
     radioPanel.add(cakeButton);
     radioPanel.add(iceButton);

     jframe.getContentPane().add(radioPanel);
     jframe.getContentPane().add(piclabel);
     jframe.setVisible(true); 

JOptionPane

What it is: This is a utility pane that can pop up some common warning and error messages. It’s as easy to use as JToolTip, and it works the same way. You don’t instantiate it directly, but you call a method to make it happen.

What it looks like on-screen:

JOptionPane

The code to create it: The method to show a JOptionPane takes four arguments:

  • A parent frame (null means use a default). The Pane appears below its parent.

  • The thing to display. It can be a String or an icon or a JLabel or other possibilities that are converted to String and then wrapped in a JLabel.

  • The title String to put on the Pane title bar.

  • The type of message, like ERROR_MESSAGE, WARNING_MESSAGE, or INFORMATION_MESSAGE.

Icon s = new ImageIcon("spam.jpg");
JLabel jl = new JLabel("Are you getting enough?", s,JLabel.CENTER);

JOptionPane.showMessageDialog( null, // parent frame
                    jl,   // Object to display
                    "Plenty of spam", // title bar message
                    JOptionPane.QUESTION_MESSAGE ); 

The code to retrieve user input from it: No input comes back from this component. When the user clicks on the button, the Pane is dismissed automatically. There are a great many choices and methods that fine-tune this JComponent to let you convey exactly the nuance of information you want.

JScrollPane

What it is: Of all the JComponents, this one is probably my favorite. It works so hard for you with so little effort on your part.

A JScrollPane provides a scrollable view of any lightweight component. You just instantiate a JScrollPane with the thing you want to scroll as an argument to the constructor. Then set the ScrollPane’s preferred size with a method call, add it to your container, and you’re done! This is so much easier than messing around with individual and highly buggy scrollbars that we had in JDK 1.0.

By default, a scroll pane attempts to size itself so that its client displays at its preferred size. Many components have a simple preferred size that’s big enough to display the entire component. You can customize a scroll pane with many refinements on how much to scroll, which of the scroll bars to show, custom decorations around the sides, and so on. The visible area in the Pane is called the “viewport.”

What it looks like on-screen:

JScrollPane

The code to create it: In this code, we put the JPanel subclass that we created earlier into a JScrollPane.

MyJPanel mjp = new MyJPanel();
JScrollPane jsp = new JScrollPane( mjp );
jsp.setPreferredSize( new Dimension(150, 150));
jframe.getContentPane().add(jsp); 

The code to retrieve user input from it: You won’t need to interact with your scroll pane very frequently, as it does so much of the right thing by default. However, you can implement the Scrollable interface if your enthusiasm extends to wanting to get callbacks for individual clicks on the scroll bars.

JTabbedPane

What it is: A Tabbed Pane is a component that lets you economize on-screen real estate. It simulates a folder with tabbed page dividers. You have a series of “tabs” (labels) along the top, associated with Components on a larger rectangular area beneath. By clicking on a tab label, you bring its associated component to the front. We’ll show an example using the JEditorPane and the JPanel we already saw.

What it looks like on-screen:

JTabbedPane

You can make the tabs appear on any of the four sides of the TabbedPane. You can have even more than one row of tabs, but the human factors of that are so appalling that Sun corrected it in JDK 1.4. When you have multiple rows, any tab that’s clicked moves to the bottom row of tabs. As a result, clicking on some tabs causes all of them to change places. To prevent this, you can pass an argument to the constructor saying that you want tabs to scroll, not to wrap, when you exceed a line.

The code to create it:

// set up the editor pane, as before
     JEditorPane jep =null;
     try {
          jep = new JEditorPane( "file:///tmp/know.html" );
     } catch (Exception e) {System.out.println("error: "+e); }

     jep.setEditable(false); // turns off the ability to edit
     JScrollPane jsp = new JScrollPane( jep );
     jsp.setPreferredSize( new Dimension(550, 250));

// set up the JPanel, as before
     MyJPanel mjp = new MyJPanel();
     jframe.getContentPane().add(mjp);

// create a tabbed pane and add them to it.
     JTabbedPane jtp = new JTabbedPane();
     ImageIcon ic = new ImageIcon("star.gif");
     jtp.addTab("Bike", ic, mjp,
                "1989 BWM RS100/1996 Dalmatian Annie");
     jtp.addTab("Knowledge", null, jsp, "who knew?");

     jframe.getContentPane().add(jtp);
     jframe.setVisible(true);
} 

The method to add a tab and the Component together takes four arguments:

public void addTab(String title,
                    Icon icon,
                    Component component,
                    String tip) 

The title is the phrase to put on the tab. The icon is a little picture with which you can decorate the phrase. For example, on the “Bike” pane I use a star, and on the “Knowledge” pane I use null to signify no picture. The third parameter is the component that you want associated with that tab. The final parameter is a String representing tooltip text that you get for free with this component.

JEditorPane

What it is: This is a very powerful JComponent! JEditorPane allows you to display and edit documents that contain HTML, Rich Text Format, or straight Unicode characters. It formats the text and displays it.

What it looks like on-screen:

JEditorPane

You can load the component from a URL or from a String containing a URL as shown below, or from the contents of a String itself. In the following example, the JEditor pane is placed in a ScrollPane so it displays and scrolls well.

The code to create it:

JEditorPane jep =null;
try {
     jep = new JEditorPane("file:///tmp/know.html");
} catch (Exception e) {System.out.println("error: "+e); }

jep.setEditable(false); // turns off the ability to edit
JScrollPane jsp = new JScrollPane( jep );
jsp.setPreferredSize( new Dimension(550, 250));

jframe.getContentPane().add(jsp); 

Notice how trivial it is to display an HTML file and to wrap a JScrollPane around it. JEditorPane is a subclass of the less specialized JTextComponent.

Let’s quickly review the match between components and events (Table 21-2).

Table 21-2. Components and Events

Component

Event Handler Interface

Method(s) the Interface Promises

JButton

JMenu

JMenuItem

JRadioButton

JCheckBox

ActionListener

public void actionPerformed(ActionEvent e);

Component

ComponentListener

public void componentResized(ComponentEvent);

public void componentMoved(ComponentEvent);

public void componentShown(ComponentEvent);

public void componentHidden(ComponentEvent);

Container

ContainerListener

public void componentAdded(ContainerEvent);

public void componentRemoved(ContainerEvent);

Component

FocusListener

public void focusGained(FocusEvent e);

public void focusLost(FocusEvent e);

JButton

JMenu

JMenuItem

JRadioButton

JCheckBox

ItemListener

public void itemStateChanged(ItemEvent e);

Component

KeyListener

public void keyTyped(KeyEvent e);

public void keyPressed(KeyEvent e);

public void keyReleased(KeyEvent e);

Component

MouseListener

public void mouseClicked(MouseEvent e);

public void mousePressed(MouseEvent e);

public void mouseReleased(MouseEvent e);

public void mouseEntered(MouseEvent e);

public void mouseExited(MouseEvent e);

Component

MouseMotionListener

public void mouseDragged(MouseEvent e);

public void mouseMoved(MouseEvent e);

JTextField

Dialog

JDialog

Frame

JFrame

Window

JWindow

ActionListener

WindowListener

public void actionPerformed(ActionEvent e);

public void windowOpened(WindowEvent e);

public void windowClosing(WindowEvent e);

public void windowClosed(WindowEvent e);

public void windowIconified(WindowEvent e);

public void windowDeiconified(WindowEvent e):

public void windowActivated(WindowEvent e);

public void WindowDeactivated (WindowEvent e);

More about Swing Components

Table 21-2 named all the significant JComponents, and there were about forty in all (including all the subclasses of subclasses). We’ve presented, briefly, some of the more important ones here. That’s certainly enough to get you started writing GUI programs. To keep the book to a manageable size, however, and still fit in all the other information, we don’t show all of them.

Here are some pointers on how to find out more about the other components when you’re ready to. The first resource is the good (if somewhat fluid) online tutorial on Java generally, and Swing in particular, that Sun Microsystems maintains at java.sun.com/docs/books/tutorial/ui/swing/.

The second resource is the Swing section of the Java Programmers FAQ that is on this CD and is also online in a more up-to-date form at www.afu.com. The FAQ has lots of nuggets of information about Java problems that everyone initially encounters. It gives advice on solutions and workarounds.

The third resource is to buy or borrow a book that examines JFC, including the Swing components in depth. These books are frequently intimidating in size. One such book that I like is Kim Topley’s Core Java Foundation Classes (Prentice Hall, New Jersey, 1998, ISBN 0-13-080301-4). It weighs in at over 1,100 pages, so be prepared to put in a few evenings and weekends.

Finally, I have the same advice that Obi-Wan gave Luke Skywalker on his quest to defeat the forces of evil: Use the source. The Java platform is almost unique among commercial products in that the complete source code for the runtime library is distributed with the system. If you installed the compiler in C:jdk1.4fcs, then the source is in C:jdk1.4fcssrc.jar. Jar (Java archive) files have the same format as zip files, so you can unpack it by using unzip src.jar. That will put the Swing source files into the C:jdk1.4fcssrcjavaxswing directory.

Having the source is a triple blessing. You can read the code to find out how something works and what features it offers (the code is heavily commented). You can recompile the code with more of your own debugging information, and use that instead of the standard runtime library (not everyone will want to tackle this, but in fact, it is trivial to use the “update” option to jar to replace a single class file in rt.jar). You will also be exposed to the ideas, style, and designs that are used by the best Java programmers in the world. The best programmers in the world learn from each other by reading each other’s code. Now you have this opportunity, too. Seize it.

I really like Swing. It passes the golden rule of software: It’s simple to do simple things. Just be aware that all the components have many more features than are presented here and you can get some very sophisticated effects when you start combining them and using them to full advantage.

Further Reading

The first Java website that you visit should be Sun’s at java.sun.com. But the Java website that you visit most frequently should be the Java Lobby at www.javalobby.org.

The Java Lobby is an independent group representing Java developers. Led by software entrepreneur Rick Ross, the Lobby has more than 50,000 members. It is a great place for thoughtful discussion and late-breaking news on Java. You can even get advice on coding. The Java Lobby is a great resource and membership is free.

Exercises

  1. Review the javadoc-generated description of the javax.swing.SwingUtilities class. Write a program that demonstrates the use of two of the utilities in that class.

  2. Add the JEditorPane that can render html to some code that can make a socket enquiry in the HTTP protocol. Create a basic web browser in less than 150 lines of code. You can do this in one evening, and spend the rest of the year adding refinements to it.

  3. Review the class java.awt.Robot. It is intended to generate native system input events for test programs. Instead, use it to develop an automatic player for Web Wars (hard) or Minesweeper (easier).

  4. This code will grab a screen image.

    Robot ro = new Robot();
    Toolkit t = Toolkit.getDefaultToolkit();
    final Dimension d = t.getScreenSize();
    Rectangle re = new Rectangle(d.width, d.height);
    final Image image = ro.createScreenCapture( re ); 

    Look up Image I/O in the next chapter, and write code to turn this into a JPG or GIF file.

Some Light Relief—The Bible Code

A couple of chapters back, the Light Relief section ended with a praying mantis (origami), so I’ll continue the religious theme with a description of the Bible code. The concept of “Bible codes” was something that became popular in 1997, helped by a mass marketed book on the subject. It’s a completely bogus idea that there are hidden strings in the first five books of the Bible, and these hidden strings foretell the future.

The hidden strings, or Bible codes, are supposedly found by looking at individual characters of the Bible, starting at some offset, and taking every Nth letter thereafter to form a phrase. It works much better with a Bible in Hebrew because the classic written form of that language does not have any vowels. Hence, you can construct many possible phrases depending on which vowels you choose to put in and where you choose to end a word. “BLLGTS” can be interpreted as “Boil leg & toes” or “Be a li’l gutsy” or even “Bill Gates.”

When you find a Bible “code” you frequently find other related phrases around it. Of course, you can often find clouds in the sky that have shapes that look like animals, and the reason is exactly the same: people tend to see what they want to see. There’s a huge amount of sky and clouds to look at, and you can always find something if you look at enough random stuff.

I thought it would be fun to write some Bible code software in Java, so I put it on the CD. There’s a program in ible that you can run to search for arbitrary patterns in the Bible (a copy of the King James Version is also on the CD). See Figure 21-3 for the results when I set it to search for the string “Java”—a place and language unknown in biblical times.

Bible code says “Java a great blessing!”

Figure 21-3. Bible code says “Java a great blessing!”

As you can see, it has found the word along with other astonishing and highly meaningful phrases (“knowledge of Java, a great blessing, bit, net”). You can run the program for yourself and find other phrases of your choice.

One of the promoters of the Bible code concept challenged his critics to find hidden messages in non-Bible texts like Moby Dick. He thought there weren’t any. He was dead wrong!

You will find that Moby Dick contains predictions for the deaths of Indira Gandhi, President Rene Moawad of Lebanon, Martin Luther King, Chancellor Engelbert Dollfuss of Austria, Leon Trotsky, Sirhan Sirhan, John F. Kennedy, Robert Kennedy, and Princess Diana, among others! Figure 21-4 shows the Diana prediction from Moby Dick.

Bible code links Lady Di and Dodi.

Figure 21-4. Bible code links Lady Di and Dodi.

“Lady Diana, Dodi, foolishly wasted, mortal in these jaws of death!” The two likeliest conclusions follow. Either Herman Melville was the Supreme Creator of the Universe and he encoded Bible code style predictions in Moby Dick as well as in the Bible. Another option is that the notion of hidden messages encoded in revered works is a bunch of nonsense put about by some people who should know better. I don’t know about you, but I’m going with the simpler of the two explanations. Let me add that the meaninglessness of the codes doesn’t impugn the origin of the Bible. It just says that people can be wrong when they try to project their own interpretations onto any text.

Take a look at the CD directory bibleMobyDick for details. There’s a copy of Moby Dick there, along with the Bible code software to search it. I’d like to find out what hidden messages there are in the Sherlock Holmes books. This is what programmers do when they have too much time on their hands.



[1] A more descriptive name for the paintComponent() method would be how_to_draw_me().

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

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