Images

ImageIcons

An ImageIcon is a fixed size image that can be attached to a JLabel, JButton or JTabbedPane.

To include icons in an applet you should create a sub-folder in the project's "src" folder called "images" (or any other name) and copy your images into this folder. Whenever you do a build, this folder will automatically be copied into the project's "build" folder. The location of the image that is loaded in the getResource() method will be the automatically created "images" folder that is relative to the class file.

ImageIcon Example (Run Applet)

import javax.swing.*;

public class ImageIconDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        public View()
        {
            super();
            // NOTE the the getResource() method looks for files relative to the location of the .class file
            final ImageIcon redIcon = new ImageIcon(getClass().getClassLoader().getResource("images/red_bullet.gif"));

            final JButton redButton = new JButton("Red Button");
            final JLabel greenLabel = new JLabel("Green Label");

            // the code below shows two different ways to assign the icon
            redButton.setIcon(redIcon);
            greenLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/green_bullet.gif")));

            // set the position of the redButton's text relative to an ImageIcon
            redButton.setHorizontalTextPosition(SwingConstants.LEFT);  // LEFT means the text is on the left side

            this.add(redButton);
            this.add(greenLabel);
        }
    }
}

 

We can use ImageIcons to display images. Labels can be set up to hold an ImageIcon and no text. This is a useful way to display images. However, the image inside the ImageIcon is fixed and cannot be minipulated once it has be initialised. In particular, an ImageLabel will not resize itself to fit it holding component. Instead, the compoent will resize to fit an ImageLabel. This means that ImageIcons need to be the correct size before they are used in code. The example below shows two labels automatically resizing to accomodate their respective ImageIcons.

Automatic Resizing of Labels to Accomodate ImageIcon Size Example: (Run Applet)

import javax.swing.*;

public class ImageIconSizeDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        public View()
        {
            super();

            final JLabel redLabel = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("images/red_bullet.gif")));
            final JLabel koalaLabel = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("images/koala.jpg")));

            this.add(redLabel);
            this.add(koalaLabel);
        }
    }
}

Image

We can use the Image class to overcome the limitations of ImageIcons. Images can be drawn onto any surface and they can be resized. We shall see later that the pixels in an image can be directly minipulated.

Java supports JPEG, GIF and PNG bitmapped graphics files. Applets do not support Microsoft .BMP files.

There are two ways to load an image.

Use the JApplet getImage() method
The JApplet class has a method called getImage() that can load an Image. This method is restrictive, as it can only be used in Applets. In the example below, the JApplet.getImage() method takes as a parameter the method getDocumentBase(). This method returns the folder that the applet's parent html document resides in. Apart from the example below, we shall not use this method in these notes.
Use the ImageIcon getImage() method
The ImageIcon class has a method called getImage() that can load an Image. This method will work for both applets and applications. We shall use this method in these notes.

The example below shows the use of the JApplet.getImage() and the ImageIcon.getImage() methods.

Run example: (Run Applet)

import java.awt.*;
import javax.swing.*;

public class GetImageDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        public View()
        {
            super();
        }

        @Override
        public void paintComponent(Graphics g)
        {
            // Note: getDocumentBase() returns the folder that the applet's parent .html document resides in.
            final Image appletImage = getImage(getDocumentBase(), "classes/images/red_bullet.gif");
            final Image iconImage = new ImageIcon(getClass().getClassLoader().getResource("images/green_bullet.gif")).getImage();

            g.drawImage(appletImage, 0, 0, 100, 100, this);
            g.drawImage(iconImage, 150, 0, 100, 100, this);
        }
    }
}

Drawing an Image onto a Component

Use the drawImage() method to display the Image. The drawImage() method draws the specified image with its top left corner at (x, y) in the graphics context's coordinate space.

The drawImage() method can also be used for scaling.

For example: (Run Applet)

import javax.swing.*;
import java.awt.*;

public class DrawImageDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        public View()
        {
            super();

        }

        @Override
        public void paintComponent(Graphics g)
        {
            final Image gif = (new ImageIcon(getClass().getClassLoader().getResource("images/world.gif"))).getImage();
            final int width = gif.getWidth(this);
            final int height = gif.getHeight(this);

            g.drawImage(gif, 1, 1, width, height, this);
            g.drawImage(gif, 1, height + 5, width * 4, height / 2, this);
        }
    }
}

Media Trackers

Java uses threads to load image files. Rather than having to wait for an image file to be loaded, an applet will assign a thread to load the image file. The applet is then free to continue and do other things.

It might take a considerable length of time to load a graphics file over the WWW. We can use a MediaTracker to avoid the gradual building up of the graphics image.

The MediaTracker class traces the status of graphics files.

To use the MediaTracker, create an instance of the MediaTracker class and then call the addImage() method for each image to be tracked by the MediaTracker.

A MediaTracker can have more than one image assigned to it. Each image can be assigned a unique identifier.

The identifier:

The syntax for addImage() is:

addlmage(Image image, int id)
addImage(Image image, int id, int w, int h)

To check if a graphics files assigned to a MediaTracker has been loaded use:

boolean checkID(int id)  

To check if all the graphics files assigned to a MediaTracker have been loaded use:

boolean checkAll()  

To wait for all the graphics files assigned to a specific MediaTracker ID to be loaded use:

waitForID(int id)                    // wait indefinitely
boolean waitForID(int id, 1ong ms)   // the maximum number of miliseconds to wait. 
                                     // If it times out return false

To wait for all the graphics files assigned to a MediaTracker to be loaded use:

waitForAll()                 // wait indefinitely 
boolean waitForAll(1ong ms)  // the maximum number of miliseconds to wait. 
                             // If it times out return false 

For example: (Run Applet)

import java.awt.*;
import javax.swing.*;

public class MediaTrackerDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        public View()
        {
            super();

        }

        @Override
        public void paintComponent(Graphics g)
        {
            final Image gif = new ImageIcon(getClass().getClassLoader().getResource("images/world.gif")).getImage();

            final MediaTracker gifTracker = new MediaTracker(this);
            final int trackerId = 1;
            gifTracker.addImage(gif, trackerId);
            try
            {
                gifTracker.waitForID(trackerId);
            }
            catch (InterruptedException e)
            {
            }

            final int width = gif.getWidth(this);
            final int height = gif.getHeight(this);

            g.drawImage(gif, 1, 1, this);
            g.drawImage(gif, 1, height + 5, width * 4, height / 2, this);
        }
    }
}

Animations

An animation is a sequence of graphics images. Use an array of Images to hold the frames of an animation.

For example: (Run Applet)

import java.awt.*;
import javax.swing.*;

public class AnimationDemo extends JApplet
{
    private final View view = new View();

    @Override
    public void init()
    {
        this.setContentPane(this.view);
    }

    @Override
    public void start()
    {
        this.view.setCurImage(0);  // reset animation to first image
    }

    public class View extends JPanel
    {
        private final int numImages = 18;
        private final Image gif[] = new Image[numImages];
        private int curImage = 0;

        public View()
        {
            super();
            for (int i = 0; i < this.numImages; i++)
            {
                this.gif[i] = new ImageIcon(getClass().getClassLoader().getResource("images/img" + i + ".gif")).getImage();
            }
        }

        public void setCurImage(int curImage)
        {
            this.curImage = curImage;
        }

        @Override
        public void paintComponent(Graphics g)
        {
            g.drawImage(this.gif[this.curImage], 1, 1, this);
            if (++this.curImage == this.numImages)
            {
                this.curImage = 0;
            }

            try
            {
                Thread.sleep(80);
            }
            catch (InterruptedException e)
            {
            }
            this.repaint();
        }
    }
}

We can avoid the jerky build-up of images by using a MediaTracker.

For Example. (Run Applet)

import java.awt.*;
import javax.swing.*;

public class MediaTrackerAnimationDemo extends JApplet
{
    private final View view = new View();

    @Override
    public void init()
    {
        this.setContentPane(this.view);
    }

    @Override
    public void start()
    {
        this.view.setCurImage(0);  // reset animation to first image
    }

    public class View extends JPanel
    {
        private final int numImages = 18;
        private final Image gif[] = new Image[numImages];
        private final MediaTracker animationTracker = new MediaTracker(this);
        private int curImage = 0;

        public View()
        {
            super();

            for (int i = 0; i < this.numImages; i++)
            {
                this.gif[i] = new ImageIcon(getClass().getClassLoader().getResource("images/img" + i + ".gif")).getImage();
                animationTracker.addImage(this.gif[i], 1);
            }
        }

        public void setCurImage(int curImage)
        {
            this.curImage = curImage;
        }

        @Override
        public void paintComponent(Graphics g)
        {
            if (this.animationTracker.checkID(1, true))
            {
                g.drawImage(this.gif[this.curImage], 1, 1, this);
                if (++this.curImage == this.numImages)
                {
                    this.curImage = 0;
                }
            }
            else
            {
                g.drawString("Loading images...", 100, 100);
            }

            if (++this.curImage == this.numImages)
            {
                this.curImage = 0;
            }

            try
            {
                Thread.sleep(80);
            }
            catch (InterruptedException e)
            {
            }
            this.repaint();
        }
    }
}

Clearing The Painted Background

The default super.paintComponent() method clears its background. Therefore, whatever was drawn previously will be overwritten on the screen after the next call to painComponent(). This is show in the example below.

Example of clearing the background when calling paintComponent() method (Run Applet)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintWithCallToSuperDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel implements MouseListener, MouseMotionListener
    {
        private final Image gif;
        private final int width = 100;
        private final int height = 100;
        private int curX = 1;
        private int curY = 1;
        private final Rectangle rect = new Rectangle(curX, curY, width, height);
        private int offsetX = 0;
        private int offsetY = 0;

        public View()
        {
            super();
            this.gif = new ImageIcon(getClass().getClassLoader().getResource("images/world.gif")).getImage();
            this.setBackground(Color.red);

            this.addMouseListener(this);
            this.addMouseMotionListener(this);
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.drawImage(this.gif, 0, 0, getWidth(), getHeight(), this);
            g.drawImage(this.gif, this.curX, this.curY, this.width, this.height, this);
        }

        @Override
        public void mouseDragged(MouseEvent e)
        {
            final int x = e.getX();
            final int y = e.getY();
            if (this.rect.contains(x, y))
            {
                this.curX = x - this.offsetX;
                this.curY = y - this.offsetY;
                this.rect.setBounds(this.curX, this.curY, this.width, this.height);
                this.repaint();
            }
        }

        @Override
        public void mousePressed(MouseEvent e)
        {
            final int x = e.getX();
            final int y = e.getY();
            if (this.rect.contains(x, y))
            {
                this.offsetX = x - this.curX;
                this.offsetY = y - this.curY;
            }
        }

        @Override
        public void mouseClicked(MouseEvent me)
        {
        }

        @Override
        public void mouseReleased(MouseEvent me)
        {
        }

        @Override
        public void mouseEntered(MouseEvent me)
        {
        }

        @Override
        public void mouseExited(MouseEvent me)
        {
        }

        @Override
        public void mouseMoved(MouseEvent me)
        {
        }
    }
}

 

Removing the call to super.paintComponent() method will result in whatever was drawn previously remaining on the screen. This is show in the example below.

Example of leaving the background in tack between calls to the paintComponent() method (Run Applet)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintWithoutCallToSuperDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel implements MouseListener, MouseMotionListener
    {
        private final Image gif;
        private final int width = 100;
        private final int height = 100;
        private int curX = 1;
        private int curY = 1;
        private final Rectangle rect = new Rectangle(curX, curY, width, height);
        private int offsetX = 0;
        private int offsetY = 0;

        public View()
        {
            super();
            this.gif = new ImageIcon(getClass().getClassLoader().getResource("images/world.gif")).getImage();
            this.setBackground(Color.red);

            this.addMouseListener(this);
            this.addMouseMotionListener(this);
        }

        @Override
        public void paintComponent(Graphics g)
        {
            //  super.paintComponent(g);
            g.drawImage(this.gif, 0, 0, getWidth(), getHeight(), this);
            g.drawImage(this.gif, this.curX, this.curY, this.width, this.height, this);
        }

        @Override
        public void mouseDragged(MouseEvent e)
        {
            final int x = e.getX();
            final int y = e.getY();
            if (this.rect.contains(x, y))
            {
                this.curX = x - this.offsetX;
                this.curY = y - this.offsetY;
                this.rect.setBounds(this.curX, this.curY, this.width, this.height);
                this.repaint();
            }
        }

        @Override
        public void mousePressed(MouseEvent e)
        {
            final int x = e.getX();
            final int y = e.getY();
            if (this.rect.contains(x, y))
            {
                this.offsetX = x - this.curX;
                this.offsetY = y - this.curY;
            }
        }

        @Override
        public void mouseClicked(MouseEvent me)
        {
        }

        @Override
        public void mouseReleased(MouseEvent me)
        {
        }

        @Override
        public void mouseEntered(MouseEvent me)
        {
        }

        @Override
        public void mouseExited(MouseEvent me)
        {
        }

        @Override
        public void mouseMoved(MouseEvent me)
        {
        }
    }
}

Double Buffering

The Image class can be used for offscreen graphics.

Use the getGraphics() method to place a graphics context into an Image. The getGraphics() method can only be called for offscreen images, which must be created with the createImage() method.

To create an empty Image (double buffer), use the createImage() method from the Component class.

The syntax for createImage() is:

Image createImage(int width, int height)

 

Image Maps

An image map is an image that has hot areas that the user can click on to trigger an event. For example, when a user positions the mouse over a hot area a descriptive message can be displayed in the status area of the browser.

We can detect if the mouse is positioned over a Component (such as a Canvas) using the Component's contains() method.


boolean contains(int x, int y)

We can draw a Rectangle or Polygon at any location on top of any Component. We can then use the Rectangle'sor Polygon's contains() method to detect that the mouse has moved over an area within a Component. Rectangles can be used to bound Images drawn on a Component's graphics context.

Image Map Example: (Run Applet)

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ImageMapDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel implements MouseMotionListener
    {
        private final int x[] =
        {
            177, 175, 191, 202, 209, 216, 215, 208, 196
        };
        private final int y[] =
        {
            165, 250, 246, 239, 229, 218, 203, 185, 171
        };
        private final Polygon poly = new Polygon(this.x, this.y, 9);
        private final Rectangle rect = new Rectangle(125, 29, 56, 78);
        private final Image gif = new ImageIcon(getClass().getClassLoader().getResource("images/halfAdder.gif")).getImage();

        public View()
        {
            super();
            this.addMouseMotionListener(this);
        }

        @Override
        public void paintComponent(Graphics g)
        {
            g.drawImage(this.gif, 0, 0, this);
        }

        @Override
        public void mouseDragged(MouseEvent me)
        {
        }

        @Override
        public void mouseMoved(MouseEvent e)
        {
            final int x = e.getX();
            final int y = e.getY();
            if (this.rect.contains(x, y))
            {
                showStatus("NOR gate selected");
            }
            else if (this.poly.contains(x, y))
            {
                showStatus("AND gate selected");
            }
            else
            {
                showStatus("No gate selected");
            }
        }
    }
}
 
<div align="center"><a href="../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>