IconDemoApplet.java Source code

Java tutorial

Introduction

Here is the source code for IconDemoApplet.java

Source

/* From http://java.sun.com/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.net.URL;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class IconDemoApplet extends JApplet implements ActionListener {
    Vector pictures;

    JButton previousButton;

    JButton nextButton;

    JLabel photographLabel;

    JLabel captionLabel;

    JLabel numberLabel;

    int current = 0;

    int widthOfWidest = 0;

    int heightOfTallest = 0;

    String imagedir = null;

    public void init() {
        //Parse the applet parameters
        pictures = parseParameters();

        //If the applet tag doesn't provide an "IMAGE0" parameter,
        //display an error message.
        if (pictures.size() == 0) {
            captionLabel = new JLabel("No images listed in applet tag.");
            captionLabel.setHorizontalAlignment(JLabel.CENTER);
            getContentPane().add(captionLabel);
            return;
        }

        //NOW CREATE THE GUI COMPONENTS

        //A label to identify XX of XX.
        numberLabel = new JLabel("Picture " + (current + 1) + " of " + pictures.size());
        numberLabel.setHorizontalAlignment(JLabel.LEFT);
        numberLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5));

        //A label for the caption.
        final Photo first = (Photo) pictures.firstElement();
        captionLabel = new JLabel(first.caption);
        captionLabel.setHorizontalAlignment(JLabel.CENTER);
        captionLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));

        //A label for displaying the photographs.
        photographLabel = new JLabel("Loading first image...");
        photographLabel.setHorizontalAlignment(JLabel.CENTER);
        photographLabel.setVerticalAlignment(JLabel.CENTER);
        photographLabel.setVerticalTextPosition(JLabel.CENTER);
        photographLabel.setHorizontalTextPosition(JLabel.CENTER);
        photographLabel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLoweredBevelBorder(),
                BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        photographLabel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0),
                photographLabel.getBorder()));

        //Set the preferred size for the picture,
        //with room for the borders.
        Insets i = photographLabel.getInsets();
        photographLabel.setPreferredSize(
                new Dimension(widthOfWidest + i.left + i.right, heightOfTallest + i.bottom + i.top));

        //Create the next and previous buttons.
        ImageIcon nextIcon = new ImageIcon(getURL(imagedir + "right.gif"));
        ImageIcon dimmedNextIcon = new ImageIcon(getURL(imagedir + "dimmedRight.gif"));
        ImageIcon previousIcon = new ImageIcon(getURL(imagedir + "left.gif"));
        ImageIcon dimmedPreviousIcon = new ImageIcon(getURL(imagedir + "dimmedLeft.gif"));

        previousButton = new JButton("Previous Picture", previousIcon);
        previousButton.setDisabledIcon(dimmedPreviousIcon);
        previousButton.setVerticalTextPosition(AbstractButton.CENTER);
        previousButton.setHorizontalTextPosition(AbstractButton.RIGHT);
        previousButton.setMnemonic(KeyEvent.VK_P);
        previousButton.setActionCommand("previous");
        previousButton.addActionListener(this);
        previousButton.setEnabled(false);

        nextButton = new JButton("Next Picture", nextIcon);
        nextButton.setDisabledIcon(dimmedNextIcon);
        nextButton.setVerticalTextPosition(AbstractButton.CENTER);
        nextButton.setHorizontalTextPosition(AbstractButton.LEFT);
        nextButton.setMnemonic(KeyEvent.VK_N);
        nextButton.setActionCommand("next");
        nextButton.addActionListener(this);

        //Lay out the GUI.
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();

        Container contentPane = getContentPane();
        contentPane.setLayout(layout);

        c.gridwidth = GridBagConstraints.REMAINDER;
        c.fill = GridBagConstraints.HORIZONTAL;
        layout.setConstraints(numberLabel, c);
        contentPane.add(numberLabel);

        layout.setConstraints(captionLabel, c);
        contentPane.add(captionLabel);

        c.gridwidth = GridBagConstraints.REMAINDER;
        c.fill = GridBagConstraints.BOTH;
        layout.setConstraints(photographLabel, c);
        contentPane.add(photographLabel);

        c.gridwidth = GridBagConstraints.RELATIVE;
        c.fill = GridBagConstraints.HORIZONTAL;
        layout.setConstraints(previousButton, c);
        contentPane.add(previousButton);

        c.gridwidth = GridBagConstraints.REMAINDER;
        layout.setConstraints(nextButton, c);
        contentPane.add(nextButton);

        //Start loading the image for the first photograph now.
        //The loadImage method uses a SwingWorker
        //to load the image in a separate thread.
        loadImage(imagedir + first.filename, current);
    }

    //User clicked either the next or the previous button.
    public void actionPerformed(ActionEvent e) {
        //Show loading message.
        photographLabel.setIcon(null);
        photographLabel.setText("Loading image...");

        //Compute index of photograph to view.
        if (e.getActionCommand().equals("next")) {
            current += 1;
            if (!previousButton.isEnabled())
                previousButton.setEnabled(true);
            if (current == pictures.size() - 1)
                nextButton.setEnabled(false);
        } else {
            current -= 1;
            if (!nextButton.isEnabled())
                nextButton.setEnabled(true);
            if (current == 0)
                previousButton.setEnabled(false);
        }

        //Get the photo object.
        Photo pic = (Photo) pictures.elementAt(current);

        //Update the caption and number labels.
        captionLabel.setText(pic.caption);
        numberLabel.setText("Picture " + (current + 1) + " of " + pictures.size());

        //Update the photograph.
        ImageIcon icon = pic.getIcon();
        if (icon == null) { //haven't viewed this photo before
            loadImage(imagedir + pic.filename, current);
        } else {
            updatePhotograph(current, pic);
        }
    }

    //Must be invoked from the event-dispatching thread.
    private void updatePhotograph(int index, Photo pic) {
        ImageIcon icon = pic.getIcon();

        photographLabel.setToolTipText(pic.filename + ": " + icon.getIconWidth() + " X " + icon.getIconHeight());
        photographLabel.setIcon(icon);
        photographLabel.setText("");
    }

    //Load an image in a separate thread.
    private void loadImage(final String imagePath, final int index) {
        final SwingWorker worker = new SwingWorker() {
            ImageIcon icon = null;

            public Object construct() {
                icon = new ImageIcon(getURL(imagePath));
                return icon; //return value not used by this program
            }

            //Runs on the event-dispatching thread.
            public void finished() {
                Photo pic = (Photo) pictures.elementAt(index);
                pic.setIcon(icon);
                if (index == current)
                    updatePhotograph(index, pic);
            }
        };
        worker.start();
    }

    protected URL getURL(String filename) {
        URL codeBase = this.getCodeBase();
        URL url = null;

        try {
            url = new URL(codeBase, filename);
        } catch (java.net.MalformedURLException e) {
            System.out.println("Couldn't create image: " + "badly specified URL");
            return null;
        }

        return url;
    }

    protected Vector parseParameters() {
        Vector pix = new Vector(10); //start with 10, grows if necessary
        int i = 0; //parameters index must start at 0
        String paramName = "IMAGE" + i;
        String paramValue;

        while ((paramValue = getParameter(paramName)) != null) {
            Photo pic = new Photo(paramValue, getCaption(i), getWidth(i), getHeight(i));
            pix.addElement(pic);
            i++;
            paramName = "IMAGE" + i;
        }

        //Get the name of the directory that contains the image files.
        imagedir = getParameter("IMAGEDIR");
        if (imagedir != null)
            imagedir = imagedir + "/";

        return pix;
    }

    protected String getCaption(int i) {
        return getParameter("CAPTION" + i);
    }

    protected int getWidth(int i) {
        int width = 0;
        String widthString = getParameter("WIDTH" + i);
        if (widthString != null) {
            try {
                width = Integer.parseInt(widthString);
            } catch (NumberFormatException e) {
                width = 0;
            }
        } else {
            width = 0;
        }
        if (width > widthOfWidest)
            widthOfWidest = width;
        return width;
    }

    protected int getHeight(int i) {
        int height = 0;
        String heightString = getParameter("HEIGHT" + i);
        if (heightString != null) {
            try {
                height = Integer.parseInt(heightString);
            } catch (NumberFormatException e) {
                height = 0;
            }
        } else {
            height = 0;
        }
        if (height > heightOfTallest)
            heightOfTallest = height;
        return height;
    }

    public String[][] getParameterInfo() {
        String[][] info = { { "IMAGEDIR", "string", "directory containing image files" },
                { "IMAGEN", "string", "filename" }, { "CAPTIONN", "string", "caption" },
                { "WIDTHN", "integer", "width of image" }, { "HEIGHTN", "integer", "height of image" }, };
        return info;
    }
}

class Photo {
    public String filename;

    public String caption;

    public int width;

    public int height;

    public ImageIcon icon;

    public Photo(String filename, String caption, int w, int h) {
        this.filename = filename;
        if (caption == null)
            this.caption = filename;
        else
            this.caption = caption;
        width = w;
        height = h;
        icon = null;
    }

    public void setIcon(ImageIcon i) {
        icon = i;
    }

    public ImageIcon getIcon() {
        return icon;
    }
}

/**
 * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an
 * abstract class that you subclass to perform GUI-related work in a dedicated
 * thread. For instructions on and examples of using this class, see:
 * 
 * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
 * 
 * Note that the API changed slightly in the 3rd version: You must now invoke
 * start() on the SwingWorker after creating it.
 */

abstract class SwingWorker {
    private Object value; // see getValue(), setValue()

    /**
     * Class to maintain reference to current worker thread under separate
     * synchronization control.
     */
    private static class ThreadVar {
        private Thread thread;

        ThreadVar(Thread t) {
            thread = t;
        }

        synchronized Thread get() {
            return thread;
        }

        synchronized void clear() {
            thread = null;
        }
    }

    private ThreadVar threadVar;

    /**
     * Get the value produced by the worker thread, or null if it hasn't been
     * constructed yet.
     */
    protected synchronized Object getValue() {
        return value;
    }

    /**
     * Set the value produced by worker thread
     */
    private synchronized void setValue(Object x) {
        value = x;
    }

    /**
     * Compute the value to be returned by the <code>get</code> method.
     */
    public abstract Object construct();

    /**
     * Called on the event dispatching thread (not on the worker thread) after
     * the <code>construct</code> method has returned.
     */
    public void finished() {
    }

    /**
     * A new method that interrupts the worker thread. Call this method to force
     * the worker to stop what it's doing.
     */
    public void interrupt() {
        Thread t = threadVar.get();
        if (t != null) {
            t.interrupt();
        }
        threadVar.clear();
    }

    /**
     * Return the value created by the <code>construct</code> method. Returns
     * null if either the constructing thread or the current thread was
     * interrupted before a value was produced.
     * 
     * @return the value created by the <code>construct</code> method
     */
    public Object get() {
        while (true) {
            Thread t = threadVar.get();
            if (t == null) {
                return getValue();
            }
            try {
                t.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // propagate
                return null;
            }
        }
    }

    /**
     * Start a thread that will call the <code>construct</code> method and
     * then exit.
     */
    public SwingWorker() {
        final Runnable doFinished = new Runnable() {
            public void run() {
                finished();
            }
        };

        Runnable doConstruct = new Runnable() {
            public void run() {
                try {
                    setValue(construct());
                } finally {
                    threadVar.clear();
                }

                SwingUtilities.invokeLater(doFinished);
            }
        };

        Thread t = new Thread(doConstruct);
        threadVar = new ThreadVar(t);
    }

    /**
     * Start the worker thread.
     */
    public void start() {
        Thread t = threadVar.get();
        if (t != null) {
            t.start();
        }
    }
}