Code
class ImageCaptionLabel extends JLabel implements HierarchyListener {
private float alpha = 0.0f;
private javax.swing.Timer animator;
private int yy = 0;
private JTextArea textArea = new JTextArea() {
@Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
//@Override public boolean contains(int x, int y) {
// return false;
//}
};
public ImageCaptionLabel(String caption, Icon icon) {
setIcon(icon);
textArea.setFont(textArea.getFont().deriveFont(11f));
textArea.setText(caption);
textArea.setOpaque(false);
textArea.setEditable(false);
//textArea.setFocusable(false);
textArea.setBackground(new Color(0,0,0,0));
textArea.setForeground(Color.WHITE);
textArea.setBorder(BorderFactory.createEmptyBorder(2,4,4,4));
MouseAdapter ma = new MouseAdapter() {
@Override public void mouseEntered(MouseEvent e) {
dispatchMouseEvent(e);
}
@Override public void mouseExited(MouseEvent e) {
dispatchMouseEvent(e);
}
private void dispatchMouseEvent(MouseEvent e) {
Component src = e.getComponent();
Component tgt = ImageCaptionLabel.this;
tgt.dispatchEvent(SwingUtilities.convertMouseEvent(src, e, tgt));
}
};
textArea.addMouseListener(ma);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(222,222,222)),
BorderFactory.createLineBorder(Color.WHITE, 4)));
setLayout(new OverlayLayout(this) {
@Override public void layoutContainer(Container parent) {
//Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
if(ncomponents == 0) return;
int width = parent.getWidth(); // - (insets.left + insets.right);
int height = parent.getHeight(); // - (insets.left + insets.right);
int x = 0; //insets.left; int y = insets.top;
//for(int i=0;i < ncomponents;i++) {
Component c = parent.getComponent(0); //= textArea;
c.setBounds(x, height-yy, width, c.getPreferredSize().height);
//}
}
});
add(textArea);
addMouseListener(new MouseAdapter() {
private int delay = 4;
private int count = 0;
@Override public void mouseEntered(MouseEvent e) {
if(animator!=null && animator.isRunning() ||
yy==textArea.getPreferredSize().height) return;
final double h = (double)textArea.getPreferredSize().height;
animator = new javax.swing.Timer(delay, new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
double a = easeInOut(++count/h);
yy = (int)(.5d+a*h);
textArea.setBackground(new Color(0f,0f,0f,(float)(0.6*a)));
if(yy >= textArea.getPreferredSize().height) {
yy = textArea.getPreferredSize().height;
animator.stop();
}
revalidate();
repaint();
}
});
animator.start();
}
@Override public void mouseExited(MouseEvent e) {
if(animator!=null && animator.isRunning() ||
contains(e.getPoint()) && yy==textArea.getPreferredSize().height) {
return;
}
final double h = (double)textArea.getPreferredSize().height;
animator = new javax.swing.Timer(delay, new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
double a = easeInOut(--count/h);
yy = (int)(.5d+a*h);
textArea.setBackground(new Color(0f,0f,0f,(float)(0.6*a)));
if(yy <= 0) {
yy = 0;
animator.stop();
}
revalidate();
repaint();
}
});
animator.start();
}
});
addHierarchyListener(this);
}
@Override public void hierarchyChanged(HierarchyEvent e) {
if((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED)!=0 &&
animator!=null && !isDisplayable()) {
animator.stop();
}
}
//http://www.anima-entertainment.de/math-easein-easeout-easeinout-and-bezier-curves
//coders≫ Blog Archive ≫ Math: EaseIn EaseOut, EaseInOut and Bezier Curves
public double easeInOut(double t) {
if(t < 0.5d) {
return 0.5d*Math.pow(t*2d, 3d);
}else{
return 0.5d*(Math.pow(t*2d-2d, 3d) + 2d);
}
}
}