I had not attempted to make a GUI component in Swing fade out and in before, and this post made me want to find out how to do it. I knew that since fading inherently takes time, whatever method I'd use would have to utilize a separate thread that would add Runnable's to the Event Dispatch Thread. Fortunately I didn't have to do something complicated thanks to javax.swing.Timer, since that object runs the passed in ActionListener's actionPerformed() method on the Event Dispatch Thread.
It still seems a bit messy to me, but here's the full source code of my FadeLabel object and a simple window to run it. This should just build without issues by creating a new file called "Simple.java", pasting the below code into it and compiling using "javac Simple.java". There's a couple warnings about serialVersionUID but other than that nothing will pop up.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class FadeLabel extends JLabel
{
public static final int FADE_IN = 0;
public static final int FADE_OUT = 1;
public FadeLabel(String value)
{
super(value);
fps = 30;
fadeValue = 255;
isFading = false;
fadeState = FADE_IN;
timer = null;
}
public synchronized void startFadeOut()
{
if (fadeState == FADE_OUT) return;
timer = new Timer(1000 / fps, new FadeListener(this, FADE_OUT, 5));
timer.start();
fadeState = FADE_OUT;
}
public synchronized void startFadeIn()
{
if (fadeState == FADE_IN) return;
timer = new Timer(1000 / fps, new FadeListener(this, FADE_IN, 5));
timer.start();
fadeState = FADE_IN;
}
public void toggleFade()
{
if (fadeState == FADE_OUT)
{
startFadeIn();
}
else
{
startFadeOut();
}
}
public boolean isCurrentlyFading()
{
return isFading;
}
public ActionListener getFadeToggleListener()
{
return new FadeToggleListener(this);
}
// PRIVATE IMPLEMENTATION:
private int fadeValue;
private boolean isFading;
private int fadeState;
private int fps;
private javax.swing.Timer timer;
private boolean fade(int value, int type)
{
boolean retVal = false;
if (type == FADE_IN)
{
retVal = modifyFadeValue(value);
}
else
{
retVal = modifyFadeValue(-value);
}
if (retVal)
{
// In order to determine the color and clear out the Alpha
// value from the Color class' getRGB() method, we binary
// AND with 0x00ffffff to clear it, then bit-shift fadeValue
// by 24 and binary OR the result of the bit-shift with
// the cleared RGB values.
int colorType = this.getForeground().getRGB();
colorType = colorType & 0x00ffffff;
this.setForeground(new Color(colorType | (fadeValue << 24), true));
Dimension dim = this.getSize();
this.repaint(10, 0, 0, dim.height, dim.width);
}
return retVal;
}
private boolean modifyFadeValue(int amount)
{
if ((fadeValue == 255 && amount > 0) ||
(fadeValue == 0 && amount < 0) ||
amount == 0 ) return false;
fadeValue += amount;
if (fadeValue > 255) fadeValue = 255;
if (fadeValue < 0) fadeValue = 0;
return true;
}
private class FadeListener implements ActionListener
{
private int fadeType;
private int intensity;
private FadeLabel currentLabel;
public FadeListener(FadeLabel curLab, int fType, int intense)
{
currentLabel = curLab;
fadeType = fType;
setIntensity(intense);
}
public void setIntensity(int value)
{
if (value < 0) return;
intensity = value;
}
public void actionPerformed(ActionEvent e)
{
currentLabel.isFading = true;
if (currentLabel.fade(intensity, fadeType) == false)
{
currentLabel.isFading = false;
Timer t = (javax.swing.Timer) e.getSource();
t.stop();
}
}
}
private class FadeToggleListener implements ActionListener
{
private FadeLabel label;
public FadeToggleListener(FadeLabel l)
{
label = l;
}
public void actionPerformed(ActionEvent e)
{
if (label.isCurrentlyFading()) return;
if (label.fadeState == FADE_OUT)
{
startFadeIn();
}
else
{
startFadeOut();
}
}
}
}
public class Simple extends JPanel
{
private FadeLabel fader;
public Simple()
{
JButton but = new JButton("Toggle Fade");
fader = new FadeLabel("I can fade!");
but.addActionListener(fader.getFadeToggleListener());
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(fader);
add(but);
}
public static void main(String[] args)
{
Simple s = new Simple();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(s);
f.setSize(300, 200);
f.setVisible(true);
}
}