Moving Eyes by Gilbert Le Blanc

This is a short example of a Java Swing GUI with drawing and simple animation. The eyeballs in the GUI follow the mouse cursor as you move the cursor in the drawing area of the GUI.

Introduction

I used Windows 10 and Java 7 to create this GUI. My screen capture software doesn’t recognize the narrow borders of a Windows 10 window.

I wrote 4 Java classes for this simple example. I put the 4 Java classes together to paste as a single example. You should put these classes in separate files when you create your Swing GUI.

I used the model / view / controller model when creating this Swing GUI. This means that:

  1. The view may read values from the model.
  2. The view may not update the model.
  3. The controller will update the model.
  4. The controller will repaint / revalidate the view.

Basically, the model is ignorant of the view and controller. This allows you to change the view and controller from Swing to a web site, or an Android app.

The model / view / controller pattern allows you to focus on one part of the Swing GUI at a time. In general, you’ll create the model first, then the view, and finally the controllers. You will have to go back and add fields to the model. I guarantee that you’ll come up with something you didn’t think of when you created the first cut of the model classes.

Here’s the code:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

//http://java-articles.info/articles/?p=788
public class MovingEyes implements Runnable {

    private static final int drawingWidth = 400;
    private static final int drawingHeight = 400;
    private static final int eyeballHeight = 150;
    private static final int eyeballWidthMargin = 125;

    private DrawingPanel drawingPanel;

    private Eye[] eyes;

    private JFrame frame;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new MovingEyes());
    }

    public MovingEyes() {
        this.eyes = new Eye[2];
        this.eyes[0] = new Eye(new Point(eyeballWidthMargin, eyeballHeight));
        this.eyes[1] = new Eye(new Point(drawingWidth - eyeballWidthMargin,
                eyeballHeight));
    }

    public void run() {
        frame = new JFrame("Moving Eyes by Gilbert Le Blanc");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        drawingPanel = new DrawingPanel(drawingWidth, drawingHeight);
        frame.add(drawingPanel);

        frame.setSize(800, 600);
    
        frame.setLocationRelativeTo(null);
    
        //frame.setResizable(false);
        // frame.pack();
        // frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = -2977860217912678180L;

        private static final int eyeballOuterRadius = 50;
        private static final int eyeballInnerRadius = 20;

        public DrawingPanel(int width, int height) {
            this.addMouseMotionListener(new EyeballListener(this,
                    eyeballOuterRadius - eyeballInnerRadius - 5));
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(width, height));
        }

        // images
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.setColor(Color.BLACK);

            for (Eye eye : eyes) {
                drawCircle(g, eye.getOrigin(), eyeballOuterRadius);
                fillCircle(g, eye.getEyeballOrigin(), eyeballInnerRadius);
            }
        }

        private void drawCircle(Graphics g, Point origin, int radius) {
            g.drawOval(origin.x - radius, origin.y - radius, radius + radius,
                    radius + radius);
        }

        private void fillCircle(Graphics g, Point origin, int radius) {
            g.fillOval(origin.x - radius, origin.y - radius, radius + radius,
                    radius + radius);
        }

    }

    public class Eye {
        private final Point origin;
        private Point eyeballOrigin;

        public Eye(Point origin) {
            this.origin = origin;
            this.eyeballOrigin = origin;
        }

        public Point getEyeballOrigin() {
            return eyeballOrigin;
        }

        public void setEyeballOrigin(Point eyeballOrigin) {
            this.eyeballOrigin = eyeballOrigin;
        }

        public Point getOrigin() {
            return origin;
        }

    }

    public class EyeballListener extends MouseMotionAdapter {

        private final double eyeballDistance;

        private final DrawingPanel drawingPanel;

        public EyeballListener(DrawingPanel drawingPanel, double eyeballDistance) {
            this.drawingPanel = drawingPanel;
            this.eyeballDistance = eyeballDistance;
        }


        // mouse detector
        public void mouseMoved(MouseEvent event) {
            Point p = event.getPoint();
            for (Eye eye : eyes) {
                Point origin = eye.getOrigin();
                double theta = Math.atan2((double) (p.y - origin.y),
                        (double) (p.x - origin.x));
                int x = (int) Math.round(Math.cos(theta) * eyeballDistance)
                        + origin.x;
                int y = (int) Math.round(Math.sin(theta) * eyeballDistance)
                        + origin.y;
                eye.setEyeballOrigin(new Point(x, y));
            }

            drawingPanel.repaint();
        }

    }

}

You can use the JFrame and DrawingPanel code as a base for any Swing GUI where you need to draw.

Model

The Eye class is a Java object that holds the origin of the eye (circle) and the origin of the eyeball. The Eye class is the model in this simple example.

View

The MovingEyes class is the class that defines the JFrame. The MovingEyes class is part of the view. The main method of this class invokes the SwingUtilities invokeLater method to ensure that the Swing components are defined and modified on the Event Dispatch thread.

We use a JFrame. We do not extend a JFrame. The only time you extend a Swing component, or any Java class, is when you want to override one of the class methods. We’ll see this when I talk about the DrawingPanel.

The constructor of the MovingEyes class defines 2 instances of the Eye class. The run method defines the JFrame. The code in the run method will be similar for all Swing GUIs.

The DrawingPanel class makes up the rest of the view. The DrawingPanel class extends JPanel because we want to override the paintComponent method. The constructor of the DrawingPanel class sets the preferred size of the drawing area, and adds the mouse motion listener. The mouse motion listener is the controller of this Swing GUI.

The paintComponent method of the DrawingPanel class first calls the super paintComponent method. This maintains the Swing paint chain, and should always be the first statement of the overwritten paintComponent method.

The rest of the code in the paintComponent method of the DrawingPanel class draws the eyes. We only have drawing (painting) code in the paintComponent method. Control code belongs in the controller.

Controller

The EyeballListener class is the controller class. You can have more than one controller class in a more complicated Swing GUI.

The EyeballListener class extends the MouseMotionAdapter. You can implement the MouseMotionListener. I’m overriding one method, so the code is shorter when I extend the MouseMotionAdapter.

The mouseMoved method of the EyeballListener class fires a MouseEvent when the mouse is moved. We calculate a new position for the center of an eyeball by finding the theta angle from the center of the eye to the mouse position. The theta angle is used to calculate the new center of the eyeball.

Each Eye instance is updated separately in the for loop. After both eyes are updated, the drawing panel is repainted. This happens so fast that there’s no need for an animation loop in a separate thread.

An animation loop updates the model, draws the view, and waits for a specified period of time. You would use a separate thread for the animation loop, so that the GUI on the Event Dispatch thread stays responsive. If your GUI is not responsive, you’re probably doing too much work on the Event Dispatch thread.

Site: http://java-articles.info/articles/?p=788
Java archive: Moving Eyes by Gilbert Le Blanc.jar
Link: https://www.4shared.com/file/Qm-sr08-ei/Moving_Eyes_by_Gilbert_Le_Blan.html

Icon Demo Application Java

Mais uma aplicação para manipulação de imagens com Java que você pode da uma lida e estudada aqui http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html How to Use Icons.

//package components;

import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

// IconDemoApp.java requires the following files:
//   images/right.gif
//   images/left.gif
//   images/dimmedRight.gif
//   images/dimmedLeft.gif
// The following files are copyright 2006 spriggs.net and licenced under a
// Creative Commons Licence (http://creativecommons.org/licenses/by-sa/3.0/)
//   images/sunw01.jpg
//   images/sunw02.jpg
//   images/sunw03.jpg
//   images/sunw04.jpg
//   images/sunw05.jpg

public class IconDemoApp extends JFrame implements ActionListener {

private static final long serialVersionUID = 1L;

Vector<Photo> photos = new Vector<Photo>();

static IconDemoApp frame;

JButton previousButton;
JButton nextButton;
JLabel photographLabel;
JLabel captionLabel;
JLabel numberLabel;

int current = 0;
int widthOfWidest = 0;
int heightOfTallest = 0;

String imagedir = "images/";

public static void main(String args[]) {
String myargs[] = {
"sunw01.jpg", "Original SUNW Logo", "300", "200",
"sunw02.jpg", "The Clocktower", "275", "220",
"sunw03.jpg", "Clocktower from the West", "268", "195",
"sunw04.jpg", "The Mansion", "315", "200",
"sunw05.jpg", "Sun Auditorium", "330", "205"
};

frame = new IconDemoApp("Icon Demo Application", myargs);

}

public IconDemoApp(String title, String args[]) {
// Parse the application arguments listed as arguments in JNLP
// Must come in sets of 4: image file, file description, width, height
if (args.length % 4 != 0) {
System.out.println("Error - must specify arguments in sets of 4: " +
"image file, description of image, width, and height for each image to process.");
return;
} else {
for (int i=0; i < args.length; i++) {
String image = args[i];
String caption = args[++i];
int width = getWidth(args[++i]);
int height = getHeight(args[++i]);
Photo photo = new Photo(image, caption, height, width);
photos.addElement(photo);
}
}
init();
}

private void initializeGUI() {
// If the JNLP doesn't provide default image parameters
// display an error message
if (photos.size() == 0) {
captionLabel = new JLabel("No images listed ...");
captionLabel.setHorizontalAlignment(JLabel.CENTER);
frame.add(captionLabel);
return;
}

// Create the GUI components

// A label to identify Picture XX of XX
numberLabel = new JLabel("Picture " + (current+1) +
" of " + photos.size());
numberLabel.setHorizontalAlignment(SwingConstants.CENTER);

// A label for the caption
final Photo first = photos.firstElement();
captionLabel = new JLabel(first.caption);
captionLabel.setHorizontalAlignment(SwingConstants.CENTER);

// A label for displaying the pictures
photographLabel = new JLabel("Loading first image ...");
photographLabel.setHorizontalAlignment(SwingConstants.CENTER);
photographLabel.setBorder(BorderFactory.createEtchedBorder());
photographLabel.setPreferredSize(new java.awt.Dimension(300, 200));

// Set the preferred size for the picture, leave room for 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 = createAppImageIcon("images/right.gif",
"a right arrow");
ImageIcon dimmedNextIcon = createAppImageIcon("images/dimmedRight.gif",
"a dimmed right arrow");
ImageIcon previousIcon = createAppImageIcon("images/left.gif",
"a left arrow");
ImageIcon dimmedPreviousIcon = createAppImageIcon("images/dimmedLeft.gif",
"a dimmed left arrow");

nextButton = new JButton("Next", nextIcon);
nextButton.setDisabledIcon(dimmedNextIcon);
nextButton.setMnemonic('N');
nextButton.setBorder(BorderFactory.createEtchedBorder());
nextButton.setHorizontalTextPosition(SwingConstants.LEFT);
nextButton.setPreferredSize(new Dimension(80, 30));
nextButton.setIconTextGap(8);
nextButton.setActionCommand("next");
nextButton.addActionListener(this);

previousButton = new JButton("Previous", previousIcon);
previousButton.setDisabledIcon(dimmedPreviousIcon);
previousButton.setMnemonic('P');
previousButton.setBorder(BorderFactory.createEtchedBorder());
previousButton.setHorizontalTextPosition(SwingConstants.RIGHT);
previousButton.setPreferredSize(new java.awt.Dimension(80, 30));
previousButton.setIconTextGap(8);
previousButton.setActionCommand("previous");
previousButton.addActionListener(this);
previousButton.setEnabled(false);

// Lay out the GUI (taken from NetBeans code)
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addComponent(numberLabel, GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)
.addComponent(photographLabel, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)
.addComponent(captionLabel, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(previousButton, GroupLayout.PREFERRED_SIZE, 144, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 150, Short.MAX_VALUE)
.addComponent(nextButton, GroupLayout.PREFERRED_SIZE, 144, GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(captionLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(photographLabel, GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(numberLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(nextButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(previousButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
pack();

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

public void init() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initializeGUI();
frame.setVisible(true);
frame.setTitle("Photo Album - J. Marcos B.");
frame.setSize(widthOfWidest + 150, heightOfTallest + 150);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Tamanho fixo do programa, sem alteração
//this.setResizable(false);
// Deixa o programa no meio da tela, centralizado
frame.setLocationRelativeTo(null);

}
});
}

//User clicked either the next or 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 == photos.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 photo = photos.elementAt(current);

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

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

//Must be invoked from the event-dispatching thread
private void updatePhotograph(Photo photo) {
ImageIcon icon = photo.icon;

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

//Load an image in a worker thread
private void loadImage(final String imagePath, final int index) {
(new SwingWorker<ImageIcon, Void>() {

@Override
public ImageIcon doInBackground() {
return createAppImageIcon(imagePath, "photo #" + index);
}

@Override
public void done() {
Photo photo = photos.elementAt(index);
try {
photo.icon = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}

if (index == current) {
updatePhotograph(photo);
}
}
}).execute();
}

protected int getWidth(String swidth) {
int width = 0;
String widthString = swidth;
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(String sheight) {
int height = 0;
String heightString = sheight;
if (heightString != null) {
try {
height = Integer.parseInt(heightString);
} catch (NumberFormatException e) {
height = 0;
}
} else {
height = 0;
}
if (height > heightOfTallest)
heightOfTallest = height;
return height;
}

// Returns an ImageIcon, or null if the path was invalid
// When running  using Java Plug-in, getResourceAsStream
// is more efficient than getResource
protected static ImageIcon createAppImageIcon(String path, String description) {
// Change this to the size of
// your biggest image, in bytes
int MAX_IMAGE_SIZE = 124000;
int count = 0;
BufferedInputStream imgStream = new BufferedInputStream(
IconDemoApp.class.getResourceAsStream(path));
{
byte buf[] = new byte[MAX_IMAGE_SIZE];
try {
count = imgStream.read(buf);
} catch (IOException ieo) {
System.err.println("Couldn't read stream from file: " + path);
}

try {
imgStream.close();
} catch (IOException ieo) {
System.err.println("Can't close file " + path);
}

if (count <= 0) {
System.err.println("Empty file: " + path);
return null;
}
return new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf),
description);
//} else {
// System.err.println("Couldn't find file: " + path);
//return null;
}
}

class Photo {
public String filename;
public String caption;
public int height;
public int width;
public ImageIcon icon = null;

public Photo(String filename, String caption, int height, int width) {
this.filename = filename;
this.caption = caption;
this.height = height;
this.width = width;
}
}
}

Esse aplicativo em modo applet você pode encontrar aqui http://bip.weizmann.ac.il/course/prog2/tutorial/uiswing/misc/icon.html

Também tem mais essa aqui nesse mesmo site.

/**
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions 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 Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

/**
* This application is intended to demonstrate the loading of image files into
* icons for use in a Swing user interface. It creates a toolbar with a
* thumbnail preview of each image. Clicking on the thumbnail will show the full
* image in the main display area.
*
* IconDemoApp.java requires the following files: <br>
* The following files are copyright 2006 spriggs.net and licensed under a
* Creative Commons License (http://creativecommons.org/licenses/by-sa/3.0/) <br>
* images/sunw01.jpg <br>
* images/sunw02.jpg <br>
* images/sunw03.jpg <br>
* images/sunw04.jpg <br>
* images/sunw05.jpg <br>
*
* @author Collin Fagan
* @date 7/25/2007
* @version 2.0
*/

public class IconDemoAppGUI extends JFrame {

private static final long serialVersionUID = 1L;
private JLabel photographLabel = new JLabel();
private JToolBar buttonBar = new JToolBar();

private String imagedir = "images/";

private MissingIcon placeholderIcon = new MissingIcon();

/**
* List of all the descriptions of the image files. These correspond one to
* one with the image file names
*/
private String[] imageCaptions = { "Original SUNW Logo", "The Clocktower",
"Clocktower from the West", "The Mansion", "Sun Auditorium" };

/**
* List of all the image files to load.
*/
private String[] imageFileNames = { "sunw01.jpg", "sunw02.jpg",
"sunw03.jpg", "sunw04.jpg", "sunw05.jpg" };

/**
* Main entry point to the demo. Loads the Swing elements on the "Event
* Dispatch Thread".
*
* @param args
*/
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
IconDemoAppGUI app = new IconDemoAppGUI();
app.setVisible(true);
}
});
}

/**
* Default constructor for the demo.
*/
public IconDemoAppGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Icon Demo Application: Please Select an Image.");

// A label for displaying the pictures
photographLabel.setVerticalTextPosition(JLabel.BOTTOM);
photographLabel.setHorizontalTextPosition(JLabel.CENTER);
photographLabel.setHorizontalAlignment(JLabel.CENTER);
photographLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

// We add two glue components. Later in process() we will add thumbnail
// buttons
// to the toolbar inbetween thease glue compoents. This will center the
// buttons in the toolbar.
buttonBar.add(Box.createGlue());
buttonBar.add(Box.createGlue());

add(buttonBar, BorderLayout.SOUTH);
add(photographLabel, BorderLayout.CENTER);

setSize(400, 300);

// this centers the frame on the screen
setLocationRelativeTo(null);

// start the image loading SwingWorker in a background thread
loadimages.execute();
}

/**
* SwingWorker class that loads the images a background thread and calls
* publish when a new one is ready to be displayed.
*
* We use Void as the first SwingWroker param as we do not need to return
* anything from doInBackground().
*/
private SwingWorker<Void, ThumbnailAction> loadimages = new SwingWorker<Void, ThumbnailAction>() {

/**
* Creates full size and thumbnail versions of the target image files.
*/
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < imageCaptions.length; i++) {
ImageIcon icon;
icon = createImageIcon(imagedir + imageFileNames[i],
imageCaptions[i]);

ThumbnailAction thumbAction;
if (icon != null) {

ImageIcon thumbnailIcon = new ImageIcon(getScaledImage(
icon.getImage(), 32, 32));

thumbAction = new ThumbnailAction(icon, thumbnailIcon,
imageCaptions[i]);

} else {
// the image failed to load for some reason
// so load a placeholder instead
thumbAction = new ThumbnailAction(placeholderIcon,
placeholderIcon, imageCaptions[i]);
}
publish(thumbAction);
}
// unfortunately we must return something, and only null is valid to
// return when the return type is void.
return null;
}

/**
* Process all loaded images.
*/
@Override
protected void process(List<ThumbnailAction> chunks) {
for (ThumbnailAction thumbAction : chunks) {
JButton thumbButton = new JButton(thumbAction);
// add the new button BEFORE the last glue
// this centers the buttons in the toolbar
buttonBar.add(thumbButton, buttonBar.getComponentCount() - 1);
}
}
};

/**
* Creates an ImageIcon if the path is valid.
*
* @param String
*            - resource path
* @param String
*            - description of the file
*/
protected ImageIcon createImageIcon(String path, String description) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}

/**
* Resizes an image using a Graphics2D object backed by a BufferedImage.
*
* @param srcImg
*            - source image to scale
* @param w
*            - desired width
* @param h
*            - desired height
* @return - the new resized image
*/
private Image getScaledImage(Image srcImg, int w, int h) {
BufferedImage resizedImg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}

/**
* Action class that shows the image specified in it's constructor.
*/
private class ThumbnailAction extends AbstractAction {

/**
*
*/
private static final long serialVersionUID = 1L;
/**
* The icon if the full image we want to display.
*/
private Icon displayPhoto;

/**
* @param Icon
*            - The full size photo to show in the button.
* @param Icon
*            - The thumbnail to show in the button.
* @param String
*            - The descriptioon of the icon.
*/
public ThumbnailAction(Icon photo, Icon thumb, String desc) {
displayPhoto = photo;

// The short description becomes the tooltip of a button.
putValue(SHORT_DESCRIPTION, desc);

// The LARGE_ICON_KEY is the key for setting the
// icon when an Action is applied to a button.
putValue(LARGE_ICON_KEY, thumb);
}

/**
* Shows the full image in the main area and sets the application title.
*/
public void actionPerformed(ActionEvent e) {
photographLabel.setIcon(displayPhoto);
setTitle("Icon Demo Application: " + getValue(SHORT_DESCRIPTION).toString());
}
}
}

Que por sua vez precisa dessa classe aqui:

/**
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions 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 Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Icon;

/**
* The "missing icon" is a white box with a black border and a red x. It's used
* to display something when there are issues loading an icon from an external
* location.
*
* @author Collin Fagan
* @date 7/25/2007
*/
// http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/MissingIcon.java
public class MissingIcon implements Icon {

private int width = 32;
private int height = 32;

private BasicStroke stroke = new BasicStroke(4);

public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2d = (Graphics2D) g.create();

g2d.setColor(Color.WHITE);
g2d.fillRect(x + 1, y + 1, width - 2, height - 2);

g2d.setColor(Color.BLACK);
g2d.drawRect(x + 1, y + 1, width - 2, height - 2);

g2d.setColor(Color.RED);

g2d.setStroke(stroke);
g2d.drawLine(x + 10, y + 10, x + width - 10, y + height - 10);
g2d.drawLine(x + 10, y + height - 10, x + width - 10, y + 10);

g2d.dispose();
}

public int getIconWidth() {
return width;
}

public int getIconHeight() {
return height;
}

}

Pronto acho que é isso.

Agora as fotos:

Original SUNW Logo sunw01.jpg

The Clocktower sunw02.jpg

Clocktower from the West sunw03.jpg

The Mansion sunw04.jpg

Sun Auditorium sunw05.jpg

baixar os aplicativos aqui:

Photo Album.jar
http://www.4shared.com/file/6kS0CbPS/Photo_Album.html

Icon Demo Application.jar
http://www.4shared.com/file/5bRpR1FW/Icon_Demo_Application.html