Search code examples
javaswinganimationjapplet

Java, animate a still image in a JApplet


I am working on an assignment and I'm essentially done with the assignment, it was just a simple program to create an image map and add some audio to hot spots, I have a couple more days left and was going to try and "animate" the image.

It's a picture of a car dash board and when the user clicked on the ignition I was going to see if there is a way to make the image shake for a second. I've tried looking around here and on google but every time I searched I was getting articles from the 90's for applet's and not JApplet's.

If you could point my in the right direction on how to "animate" the image or even to a place where there may be tutorials I'd appreciate it!

Here is my code if you want to see what I'm talking about and can help me out in anyway.

public class ImageMap extends JApplet implements MouseListener{
   private Image pic;
   private Container contentPane;
   private JLabel directions;
   private Rectangle horn;
   private Rectangle vent;
   private Rectangle doorLocksUpper;
   private Rectangle window;
   private Rectangle radio;
   private Rectangle ignition;
   private int x, y;
   private AudioClip hornSound, airSound, radioClip, lockSound1, lockSound2, ignitionSound;

public void init() {        
    pic = getImage(getCodeBase(), "CarDash.jpg");
    horn = new Rectangle(250, 142, 105,104);
    vent = new Rectangle(514, 159, 204, 72);
    doorLocksUpper = new Rectangle(80, 167, 104, 58);
    window = new Rectangle(122, 243, 88, 55);
    radio = new Rectangle(514, 234, 176, 171);
    ignition = new Rectangle(465, 217, 42, 43);

    directions = new JLabel("CLICK ON: Horn, Door Locks, Air Vents, Radio & Ignition Push Start");

    //Create components
    contentPane = getContentPane();
    contentPane.setLayout(new FlowLayout());
    contentPane.add(directions, BorderLayout.NORTH);
    contentPane.addMouseListener(this);
}


//Display image on applet window
public void paint(Graphics g) {
    g.drawImage(pic, 0, 40, this);

}

public void mouseClicked(MouseEvent me) {
    //Play horn clip when car horn is clicked.
    if(horn.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "HornSound.wav");
    }
    if(vent.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "AirVent.wav");
    }
    if(ignition.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "Ignition.wav");
    }
    if(doorLocksUpper.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "DoorLocks.wav");
    }
    if(radio.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "BrownSugar.mid");
    }
    if(window.contains(me.getX(), me.getY())) {
        play(getCodeBase(), "Window.wav");
    }
}
public void mouseReleased(MouseEvent me) {}
public void mouseEntered(MouseEvent me) {}
public void mouseExited(MouseEvent me) {}
public void mousePressed(MouseEvent me) {}
}

Solution

  • Here's a really quick and useful tip, don't paint directly to a top level container like a applet. It traps you into a single use case, which doesn't always make it easier to modify or re-use.

    Instead, start by using something like a JPanel as your primary container, with this, you can add it to what ever you like, applet, window, some other container.

    While there are a number of ways you can do animation in Swing, one of the simplest (and generally safest) is to use a Swing Timer.

    This example simply uses a Swing Timer, set to update every 16ms (which is to fast for my capture software :P) which is started when you click the panel. The timer simply updates a offset value which isolates between a positive and negative value. The Timer makes use of LocalTime to calculate the length of time the Timer has been running at stops it after one second

    Shake it up baby

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.time.Duration;
    import java.time.LocalTime;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ShakeAnimation {
    
        public static void main(String[] args) {
            new ShakeAnimation();
        }
    
        public ShakeAnimation() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new ShakePane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class ShakePane extends JPanel {
    
            private Timer timer;
            private LocalTime startTime;
            private int xOffset = 0;
            private int delta = 8;
    
            private BufferedImage img;
    
            public ShakePane() {
                try {
                    img = ImageIO.read(getClass().getResource("Duke-Thumbs.jpg"));
                } catch (IOException exp) {
                    exp.printStackTrace();
                }
                timer = new Timer(16, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Duration duration = Duration.between(startTime, LocalTime.now());
                        if (duration.getSeconds() >= 1) {
                            timer.stop();
                            xOffset = 0;
                        } else {
                            xOffset *= -1;
                        }
                        repaint();
                    }
                });
                addMouseListener(new MouseAdapter() {
    
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        if (!timer.isRunning()) {
                            xOffset = delta;
                            startTime = LocalTime.now();
                            timer.start();
                        }
                    }
    
                });
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (img != null) {
                    Graphics2D g2d = (Graphics2D) g.create();
                    int x = ((getWidth() - img.getWidth()) / 2) + xOffset;
                    int y = (getHeight() - img.getHeight()) / 2;
                    g2d.drawImage(img, x, y, this);
                    g2d.dispose();
                }
            }
    
        }
    
    }
    

    See How to use Swing Timers for more details