views:

360

answers:

4

I've got class which inherits from JPanel with an image on it and i want to set up a little animation to display the panel/image and then fade it out when an event fires.

I presumably set up a thread and fire off the animation but how do I do actually do the fade?

+5  A: 

You can do the threading yourself, but it might be easier to use the Trident library to handle it. If you create a setter on your class called (say, setOpacity), you can ask trident to interpolate the "opacity" field from 1.0 to 0.0 over a specific period of time (here's some of the docs on how to use Trident).

When you're painting the image, you can do the transparency with an AlphaComposite, using the updated "opacity" value for the composite's alpha parameter. There is a Sun tutorial that includes an alpha composite example.

Ash
@Ash: +1, I was going to suggest using AlphaComposite.
Webinator
Does Trident do 'easing' of interpolation as well?
Bedwyr Humphreys
I believe it does linear interpolation (mostly?), based on this blog post by Trident's author (second to last paragraph): http://www.pushing-pixels.org/?p=1599
Ash
+1  A: 

There is some useful information describing image transparency here.

Your approach would be something like this:

  • Define a Swing Timer to fire an ActionEvent on the Event Dispatch thread every N milliseconds.
  • Add an ActionListener to the Timer which should call repaint() on your Component containing the Image.
  • Override the Component's paintComponent(Graphics) method to do the following:
    • Cast the Graphics object to a Graphics2D.
    • Set an AlphaComposite on the Graphics2D using setComposite. This controls the level of transparency.
    • Draw the image.

For each iteration of your fade-out animation you would change the values of the AlphaComposite to make the image more transparent.

Adamski
My component is a child component, when I used paintComponent, it painted the whole parent inside the JPanel, overriding paint(Graphics g) instead fixed that. Is that correct?
Bedwyr Humphreys
+2  A: 

Check out the Java Timing Framework for doing fades. One important thing to consider is that you probably want the fade to take a predetermined amount of time---which means that you need to drop frames if the machine is under too much load, or paint more often if the load is light. The Timing Framework takes care of this for you.

The example on p. 353 of Filthy Rich Clients shows you how to do this.

uckelman
+2  A: 

Here's an example using alpha transparency. You can use this composite tool to see the result of using different colors, modes and alphas.

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

public class AlphaTest extends JPanel implements ActionListener {

    private static final Font FONT = new Font("Serif", Font.PLAIN, 32);
    private static final String STRING = "Mothra alert!";
    private static final float DELTA = -0.1f;
    private static final Timer timer = new Timer(100, null);
    private float alpha = 1f;

    AlphaTest() {
        this.setPreferredSize(new Dimension(256, 96));
        this.setOpaque(true);
        this.setBackground(Color.black);
        timer.setInitialDelay(1000);
        timer.addActionListener(this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setFont(FONT);
        int xx = this.getWidth();
        int yy = this.getHeight();
        int w2 = g.getFontMetrics().stringWidth(STRING) / 2;
        int h2 = g.getFontMetrics().getDescent();
        g2d.fillRect(0, 0, xx, yy);
        g2d.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_IN, alpha));
        g2d.setPaint(Color.red);
        g2d.drawString(STRING, xx / 2 - w2, yy / 2 + h2);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        alpha += DELTA;
        if (alpha < 0) {
            alpha = 1;
            timer.restart();
        }
        repaint();
    }

    static public void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setLayout(new GridLayout(0, 1));
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new AlphaTest());
                f.add(new AlphaTest());
                f.add(new AlphaTest());
                f.pack();
                f.setVisible(true);
            }
        });
    }
}
trashgod