3

I'm writing an application that do some task and inform user upon successful completion of the task. To inform user I am using a jlabel. I want this jlabel to display the message and fadeaway after a while. I am using netbeans as my IDE.

Here is the architecture of my classes.

Abstract, GUI code

abstract class Admin extends JFrame{
  protected static jlabel lbl_message= new jlabel("some text");
  // other functions and variables

  abstarct protected void performButtonClickAction();

}

Class for implementing abstract functions and providing other functionalities.

final class AdminActionPerformer extends Admin{
  final public void performButtonClickAction(){
     // code for doin the task
     if(task is successful){
         new Thread(new Fader(Admin.lbl_message)).start();
     }
  }

 public static void main(String[] args) {
    new AdminActionPerformer().setVisible(true);
 }

}

Thread for making the Jlabel fadeaway

class Fader implements Runnable{
  javax.swing.JLabel label;
  Color c;

  Fader(javax.swing.JLabel label){
    this.label=label;
    c=label.getBackground();
  }

  public void run() {
    int alpha=label.getGraphics().getColor().getAlpha()-5;
    while(alpha>0){
        System.out.println(alpha);
        alpha-=25;
        label.getGraphics().setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha));
        label.repaint();
        try {
            Thread.sleep(50);
        } catch (InterruptedException ex) {
            Logger.getLogger(Fader.class.getName()).log(Level.SEVERE, null, ex);
        }
     }
  }
}

But the label does not fadeaway. What am I doing wrong here? Thank you :)

P.S. I have set JLabel opaque true. Is that a problem? I want to display the label with its background colour initially and then make it fade away.

Niroshan
  • 2,064
  • 6
  • 35
  • 60
  • What I immediately can see is that you should only ever update the UI from the ETD and not from some random other thread. Swing is single-threaded and such things make it go wrong in really weird places. This may or may not be the answer; there might be other issues lurking (such as that you should fade the foreground as well (the background is transparent in a JLabel anyway)), so this is a comment, not an answer. Also I can't test anything right now ;-) – Joey Jul 17 '10 at 09:57
  • thanks for the info. I was trying to get background fadeaway first, as a test, so I can apply the same technique to otherstuf. – Niroshan Jul 17 '10 at 10:16
  • I tried placing the fadeaway code inside the main thread as @Johannes Rössel suggested. But it doesnt work. I have set opaque ture. Is that a problem? I want to display the label with the background initially and then make it fade away. – Niroshan Jul 17 '10 at 10:30
  • Here's an [example][1] using alpha transparency to fade a text message. [1]:https://stackoverflow.com/questions/2234020 – trashgod Jul 17 '10 at 13:42

4 Answers4

5

If you are doing a lot of effects, you might use a swing animation library, like Trident. Here's how to fade out a label.

   JLabel label = ....;
   Timeline timeline = new Timeline(label);
   timeline.addPropertyToInterpolate("background", label.getBackground(), 
     new Color(label.getBackground().getRGB(), true));
   timeline.addPropertyToInterpolate("foreground", label.getForeground(), 
      new Color(label.getForeground().getRGB(), true));
   timeline.play();

EDIT: Updated to change the foreground/background colors, which are properties on label. However, for production code I would wrap the label in a container that can apply alpha to it's children, then you can fade in/out a component in a component-neutral way. There is a component for this in one of the animation kits, but I cannot find it right now...

mdma
  • 56,943
  • 12
  • 94
  • 128
  • 1
    And that works even though a label has no such thing as an opacity property? – Joey Jul 17 '10 at 12:55
  • Even though there is no such property on the label, using Trident is the simpleset way to accomplish this. – Eugene Ryzhikov Jul 17 '10 at 13:53
  • but when I tried to fade out my image of a single Jlabel, the result seems not good. The white background appeared into the jlabel's image, and not giving a good transition of fading out... sigh. :( – gumuruh Aug 08 '11 at 06:51
3

I agree with Johannes that updating your UI from a different Thread is likely not to work well. There are mechanisms like SwingWorker and SwingUtilities.invokeLater that might solve your wrong-thread problems.

The bigger problem I see, though, is that you're fighting with your JLabel over who paints it. The JLabel is a normal component, and whenever its container is refreshed it repaints itself, in its usual colors. This is a case of "whoever paints last, wins."

Alternative suggestion: Why not just fiddle with the label's color attribute? If you make the foreground color approach the background color, it will be seen to be fading. The label will either repaint itself when you change its color, or you can force a repaint using update() or repaint(), I keep forgetting which.

EDIT

I think I see the real reason this doesn't work. You're setting the label's graphics context's color. This has no effect! Any component that paints parts of itself will set the color, i.e. dip its brush in ink, immediately before drawing anything. And of course the color it sets up for drawing its character glyphs is the original label color. Your method would only work if the label painting code foolishly forgot to set the color before drawing.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
1

probably you could try the API method...

given with com.sun.awt.AWTUtilities tricks! :D

gumuruh
  • 2,544
  • 4
  • 33
  • 56
1

enter link description hereI was also looking for a nice way to change the contents of a JLabel by fading out and in again. The following code works quite nicely. It has no code for fading an icon yet. But this should not be too hard. Please note, that it needs the current version of the TimingFramework (timingframework-swing-4.1) to run.

I hope it might be useful.

import org.jdesktop.core.animation.timing.Animator;
import org.jdesktop.core.animation.timing.TimingSource;
import org.jdesktop.core.animation.timing.TimingTargetAdapter;
import org.jdesktop.swing.animation.timing.sources.SwingTimerTimingSource;

import javax.swing.*;
import java.awt.*;
import java.util.concurrent.TimeUnit;

public class FadingLabel extends JLabel {
    protected Animator animator;
    protected String newLabelText;

    public FadingLabel(String s, Icon icon, int i) {
        super(s, icon, i);
        initAnimator();
    }

    public FadingLabel(String s, int i) {
        super(s, i);
        initAnimator();
    }

    public FadingLabel(String s) {
        super(s);
        initAnimator();
    }

    public FadingLabel(Icon icon, int i) {
        super(icon, i);
        initAnimator();
    }

    public FadingLabel(Icon icon) {
        super(icon);
        initAnimator();
    }

    public FadingLabel() {
        super();
        initAnimator();
    }

    protected void initAnimator() {
        final TimingSource ts = new SwingTimerTimingSource();
        Animator.setDefaultTimingSource(ts);
        ts.init();
        animator = new Animator.Builder().setDuration(250, TimeUnit.MILLISECONDS).setRepeatCount(2).setRepeatBehavior(Animator.RepeatBehavior.REVERSE).setStartDirection(Animator.Direction.BACKWARD).addTarget(new TimingTargetAdapter() {

            @Override
            public void repeat(Animator source) {
                setText(newLabelText);
            }

            @Override
            public void timingEvent(Animator animator, double fraction) {
                int alpha = new Double(255 * fraction).intValue();
                setForeground(new Color(getForeground().getRed(), getForeground().getGreen(), getForeground().getBlue(), alpha));
                repaint();
            }

        }).build();
    }


    @Override
    public void setText(String s) {
        if (animator != null && !animator.isRunning()) {
            newLabelText = s;
            animator.start();
        } else {
            super.setText(s);
        }
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Torsten Löhr
  • 131
  • 1
  • 4