站内搜索: 请输入搜索关键词
当前页面: 图书首页 > JFC Swing Tutorial, The: A Guide to Constructing GUIs, Second Edition

How to Make Applets - JFC Swing Tutorial, The: A Guide to Constructing GUIs, Second Edition

Previous Section  < Day Day Up >  Next Section

How to Make Applets

This section covers JApplet,[1] a class that enables applets to use Swing components. JApplet is a subclass of java.applet.Applet, which is covered in the "Writing Applets" trail in The Java Tutorial.[2] If you've never written a regular applet before, we urge you to read that trail before proceeding with this section. The information provided there applies to all applets, including Swing applets, with a few exceptions that this section explains.

[1] JApplet API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JApplet.html.

[2] The Java Tutorial's "Writing Applets" trail is available on this book's CD and online at: http://java.sun.com/docs/books/tutorial/applets/index.html.

Any applet that contains Swing components must be implemented with a subclass of JApplet. Here's a Swing version of one of the applets that helped make the Java technology famous. Figure 1, an animation applet (in its best-known configuration), shows our mascot Duke doing cartwheels.

Figure 1. To run this applet using Java Web Start, click the TumbleItem link on the RunExamples/components.html page on the CD. You can also run it inside your browser by visiting: http://java.sun.com/docs/books/tutorial/uiswing/components/applet.html.

graphics/07fig01.gif

Note: To view this applet in your browser, you need to install Java Plug-in software. For more information, refer to the Java Plug-In home page: http://java.sun.com/products/plugin/index.html.


Features Provided by JApplet

Because JApplet is a top-level Swing container, each Swing applet has a root pane. The most noticeable effects of the root pane's presence are support for adding a menu bar and the need to use a content pane.

As described in Using Top-Level Containers (page 46) in Chapter 3, each top-level container such as a JApplet has a single content pane. The content pane makes Swing applets different from regular applets in the following ways:

  • You add components to a Swing applet's content pane, not directly to the applet. Adding Components to the Content Pane (page 48) in Chapter 3 shows you how.

  • You set the layout manager on a Swing applet's content pane, not directly on the applet.

  • The default layout manager for a Swing applet's content pane is BorderLayout. This differs from the default layout manager for Applet, which is FlowLayout.

  • You don't put painting code directly in a JApplet object. See Chapter 6, Performing Custom Painting (page 129), for examples of how to perform custom painting in applets.

Version Note: In release 1.5, we expect that invoking add or setLayout on a top-level container will be equivalent to invoking it on the content pane.


Threads in Applets

Swing components should be created, queried, and manipulated on the event-dispatching thread, but browsers don't invoke applet "milestone" methods from that thread. For this reason, the milestone methodsinit, start, stop, and destroy梥hould use the Swing-Utilities method invokeAndWait (or, if appropriate, invokeLater) so that code that refers to the Swing components is executed on the event-dispatching thread. More information about these methods and the event-dispatching thread is in How to Use Threads (page 632) in Chapter 9.

Here's an example of an init method:


public void init() {

    //Execute a job on the event-dispatching thread:

    //creating this applet's GUI.

    try {

        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {

                createGUI();

            }

        });

    } catch (Exception e) {

        System.err.println("createGUI didn't successfully complete");

    }

}



private void createGUI() {

    JLabel label = new JLabel(

                       "You are successfully running a Swing applet!");

    label.setHorizontalAlignment(JLabel.CENTER);

    label.setBorder(BorderFactory.createMatteBorder(1,1,1,1,

                                                     Color.black));

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

}

The invokeLater method is not appropriate for this implementation because it allows init to return before initialization is complete, which can cause applet problems that are difficult to debug.

The init method in TumbleItem is more complex, as the following code shows.[3] As in the first example, this init method implementation uses SwingUtilities.invokeAndWait to execute the GUI creation code on the event-dispatching thread. This init method also sets up two background threads to perform GUI-related tasks. First, it uses a Swing timer (which uses a shared thread) to fire action events whenever the animation needs to be updated. Second, it uses a SwingWorker object to create a background thread that loads the animation image files, letting the applet present a GUI before all of its resources are available.

[3] You can find the source files for TumbleItem here: JavaTutorial/uiswing/components/example-1dot4/index.html#TumbleItem.


private void createGUI() {

    ...

    animator = new Animator();

    animator.setOpaque(true);

    animator.setBackground(Color.white);

    setContentPane(animator);

    ...

}



public void init() {

    loadAppletParameters();



    try {

        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {

                createGUI();

            }

        });

    } catch (Exception e) {

        System.err.println("createGUI didn't successfully complete");

    }



    //Set up the timer that will perform the animation.

    timer = new javax.swing.Timer(speed, this);

    timer.setInitialDelay(pause);

    timer.setCoalesce(false);

    timer.start(); //Start the animation.

    //Loading the images can take quite a while, so to

    //avoid staying in init() (and thus not being able

    //to show the "Loading Images..." label) we'll

    //load the images in a SwingWorker thread.

    imgs = new ImageIcon[nimgs];

    final SwingWorker worker = new SwingWorker() {

        public Object construct() {

            ...//Load all the images...

            finishedLoading = true;

            return imgs;

        }



        //Executes in the event-dispatching thread.

        public void finished() {

            //Remove the "Loading images" label.

            animator.removeAll();

            loopslot = -1;

        }

    };

    worker.start();

}

Using Images in a Swing Applet

The Applet class provides the getImage method for loading images into an applet. This method creates and returns an Image object that represents the loaded image. Because Swing components use Icons rather than Images to refer to pictures, Swing applets tend not to use getImage but instead create instances of ImageIcon梐n icon loaded from an image file. ImageIcon comes with a code-saving benefit: It handles image tracking automatically. Refer to How to Use Icons (page 603) in Chapter 9 for more information.

The animation of Duke doing cartwheels requires 17 different pictures. The applet uses one ImageIcon per picture and loads them all in its init method. Because images can take a long time to load, the icons are loaded in a separate thread implemented by a SwingWorker object. Here's the code:


public void init() {

    ...

    imgs = new ImageIcon[nimgs];

    ...

    final SwingWorker worker = new SwingWorker() {

        public Object construct() {

            //Images are numbered 1 to nimgs,

            //but fill array from 0 to nimgs-1.

            for (int i = 0; i < nimgs; i++) {

                imgs[i] = loadImage(i+1);

            }

            finishedLoading = true;

            return imgs;

        }

        ...

    };

    worker.start();

}

...

protected ImageIcon loadImage(int imageNum) {

    String path = dir + "/T" + imageNum + ".gif";

    int MAX_IMAGE_SIZE = 2400;  //Change this to the size of

                                 //your biggest image, in bytes.

    int count = 0;

    BufferedInputStream imgStream = new BufferedInputStream(

       this.getClass().getResourceAsStream(path));

    if (imgStream != null) {

        byte buf[] = new byte[MAX_IMAGE_SIZE];

        try {

            count = imgStream.read(buf);

            imgStream.close();

        } catch (java.io.IOException ioe) {

            System.err.println("Couldn't read stream from file: " + path);

            return null;

        }

        if (count <= 0) {

            System.err.println("Empty file: " + path);

            return null;

        }

        return new ImageIcon(Toolkit.getDefaultToolkit().

                                     createImage(buf));

    } else {

        System.err.println("Couldn't find file: " + path);

        return null;

    }

}

Embedding an Applet in an HTML Page

The recommended way to include an applet in an HTML page is with the APPLET tag. The following is the APPLET tag for the cartwheeling Duke applet:


<APPLET code="TumbleItem.class"

        codebase="example-1dot4/"

        archive="tumbleClasses.jar tumbleImages.jar"

        width="600" height="95">

    <param name="maxwidth" value="120">

    <param name="nimgs" value="17">

    <param name="offset" value="-57">

    <param name="img" value="images/tumble">



Your browser is completely ignoring the &lt;APPLET&gt; tag!

</APPLET>

Version Note: Before J2SE v1.3.1_01a, Java Plug-in required the OBJECT or EMBED tag instead of the APPLET tag. Details are available through the Java Plug-in home page.[4]

[4] http://java.sun.com/products/plugin/.


To find out about the various APPLET tag parameters, refer to "Using the APPLET Tag" in The Java Tutorial.

The JApplet API

Table 1 lists the interesting methods that JApplet adds to the applet API. These methods give you access to features provided by the root pane. Other methods you might use are defined by the Component and Applet classes. See The JComponent API (page 55) in Chapter 3 for a list of commonly used Component methods and "Taking Advantage of the Applet API" in The Java Tutorial for help in using Applet methods.[5]

[5] You can find the "Taking Advantage of the Applet API" section in The Java Tutorial on the CD or online at http://java.sun.com/docs/books/tutorial/applet/appletsonly/.

Table 1. JApplet Methods

Method

Purpose


void setContentPane(Container)

Container getContentPane()

Set or get the applet's content pane. The content pane contains the applet's visible GUI components and should be opaque.


JRootPane createRootPane()

void setRootPane(JRootPane)

JRootPane getRootPane()

Create, set, or get the applet's root pane. The root pane manages the interior of the applet, including the content pane, the glass pane, and so on.


void setJMenuBar(JMenuBar)

JMenuBar getJMenuBar()

Set or get the applet's menu bar to manage a set of menus for the frame.


void setGlassPane(Component)

Component getGlassPane()

Set or get the applet's glass pane. You can use the glass pane to intercept mouse events.


void setLayeredPane(JLayeredPane)

JLayeredPane getLayeredPane()

Set or get the applet's layered pane. You can use the frame's layered pane to put components on top of or behind other components.

Applet Examples

The following table shows examples of Swing applets and where they're described.

Example

Where Described

Notes

TumbleItem

This section (page 150)

An animation applet.

HelloSwingApplet

Compiling and Running Swing Programs (page 6)

The simplest of all Swing applets梚t contains only a label.

IconDemoApplet

How to Use Icons (page 603)

An applet for showing photos.

    Previous Section  < Day Day Up >  Next Section