Monday 31 July 2006

Animated Java JLabel

today I'm going to share with you a little class I made that extends the JAVA Swing jlabel element.
With this class you'll be able to fade text in/out and cycle text to be displayed.

To better help you understand. I've attached two examples.

setTxt( "code me" ) & setInterFadeTxt( "a sandwich" )
This first 1 shows the fading between two text strings


setTxtAniam(...) Here I am using the items in the array
["s","sa","san","sand","sandw","sandwi","sandwic","sandwich"]


Ok on to the good stuff!

here I'm just extending JLabel and defining some variables that we need later
import javax.swing.JLabel;
import java.awt.Color;

public class AnimeJLabel extends JLabel
{
 private static final long serialVersionUID = 1L;
 private Color startColour;

 private Thread t;
 private boolean firstTime;
 private long waitTime;
 
 private boolean stopTxtAniamBool;
 
 private int StartR,StartG,StartB;
 private int MidR,MidG,MidB;
 private int EndR,EndG,EndB;

In the constructor you can
  1. set the colour of your text
  2. the background color of the label and
  3. *optional: the number of seconds the fade should take to complete.

 public AnimeJLabel(Color startColour,Color endColour)
 {
  this(startColour,endColour,5);
 }

 public AnimeJLabel(Color startColour,Color endColour,int sec)
 {
  this.setForeground(startColour);
  this.startColour = startColour;
  
  StartR = startColour.getRed();
  StartG = startColour.getGreen();
  StartB = startColour.getBlue();
  
  EndR = endColour.getRed();
  EndG = endColour.getGreen();
  EndB = endColour.getBlue();

  firstTime = true;
  waitTime = sec * 1000;
 }

So after you create the label you can set text at anytime using this method.
you should note that this will stop the fade/animation. Then fade in the new text
 public void setTxt(String txt)
 { 
  MidR = StartR;
  MidG = StartG;
  MidB = StartB;
  
  stopT();

  this.setForeground(startColour);
  this.setText(" "+txt);
  if( ! txt.equals(""))//if theres No text then there no need to blend
  {
   try
   {
          t = new Thread(new Runnable()
               {
                   public void run()
                   {
                 try
                 {
                  Thread.sleep(waitTime);
                  
                  while(true == start2end_colour()){
                   Thread.sleep(10);
                  }
                  
                 }
                 catch(Exception ex){
                  //System.out.println("Error:Sleep");
                  //System.out.println(ex);
                 }
                   }
               });
               t.start();
   }
   catch(Exception ex){
    System.out.println("Error:Nova_JLabel");
   }
  }
 }

with the stopTxtAniam method you can stop the Label at any time.
An example; is if you are using the label to display a waiting message and then your done so you need to get rid of it.
 public void stopTxtAniam(){
  stopTxtAniamBool = true;
 }

Here are some utility methods that are frequency used throughout class
  
 private void stopT()
 {
  if(false == firstTime){
   t.interrupt();
  }
  else{
   firstTime = false;
  }
 }
 
 private void setPlaneTxt(String txt)
 {
  this.setText(" "+txt);
 }

Unlike "setText" this will allow the current text to fade out.. and then bring the new text in
 public void setInterFadeTxt(final String txt)
 {
  stopT();
  
  try
  {
         t = new Thread(new Runnable()
              {
                  public void run(){
                try
                {
                 while(true == start2end_colour()){
                  Thread.sleep(2);
                 }
                 setPlaneTxt(txt);
                 
                 while(true == end2start_colour()){
                  Thread.sleep(2);
                 }
                }
                catch(Exception ex){          
       }
                  }
              });
              t.start();
  }
  catch(Exception ex)
  {
   System.out.println("Error:CountDown");
  }
 }

this is a very handy method that allows the label to act like a countdown timer.
this method is pretty much self explanatory. Just to clarify the "displayMessage" parameter will prefix timer
 
 public void CountDown(int Sec){
  CountDown(Sec,"","Finished");
 }
 
 public void CountDown(final int Sec,final String displayMessage,final String endMessage)
 { 
  stopT();
  
  try
  {
         t = new Thread(new Runnable()
              {
                  public void run()
                  {
                try
                {
                 for(int i = Sec-1; 0<i; i--)
                 {
                  for(int ii = 100; 0<ii; ii-=2)//go up in 2
                  {
                  setPlaneTxt(displayMessage +" "+i+"."+ii);
                  Thread.sleep(20);
                  }
                 }
                 setPlaneTxt(endMessage);
                 
                }
                catch(Exception ex){
                }
                  }
              });
              t.start();
  }
  catch(Exception ex){
   System.out.println("Error:CountDown");
  }
 }

and here's where we get our lovely typewriter effect
you should note that the time is in milliseconds and represents the time between each array element.
 public void setTxtAniam(final String [] txtArray, final long timeInMill)
 {
  stopTxtAniamBool = false;
  stopT();
  
  try
  {
         t = new Thread(new Runnable()
              {
                  public void run()
                  {
                try
                {
                 while(false == stopTxtAniamBool)
                 {
                  for(int i = 0; i<txtArray.length; i++)
                  {
                   if(false == stopTxtAniamBool)//will help to stop the aniam faster
                   {
                    setPlaneTxt(txtArray[i]);
                    Thread.sleep(timeInMill);
                   }
                  }
                 }
                 while(true == start2end_colour()){
                  Thread.sleep(10);
                 }
                 
                }
                catch(Exception ex){
                }
                  }
              });
              t.start();
  }
  catch(Exception ex){
   System.out.println("Error:setTxtAniam");
  }
 }

here are just a methods that handles the colour transform
 private boolean start2end_colour()
 {
  
  int intR = 0;
  int intG = 0;
  int intB = 0;
  
  this.setForeground(new Color(MidR,MidG,MidB));

  if(MidR == EndR)
  {  intR = 1;  }
  else if(EndR>MidR)
  {  MidR++;  }
  else// if(EndR<MidR)
  {  MidR--;  }
  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  if(MidG == EndG)
  {  intG = 1;  }
  else if(EndG>MidG)
  {  MidG++;  }
  else// if(EndG<MidG)
  {  MidG--;  }
  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  if(MidB == EndB)
  {  intB = 1;  }
  else if(EndB>MidB)
  {  MidB++;  }
  else// if(EndB<MidB)
  {  MidB--;  }
  
  if(1 == intR && 1 == intB && 1 == intG)
  {  return false;  }
  else
  {  return true;  }
 }

 private boolean end2start_colour()
  { 
   int intR = 0;
   int intG = 0;
   int intB = 0;
  
   this.setForeground(new Color(MidR,MidG,MidB));

   if(MidR == StartR)
   { intR = 1;  }
   else if(StartR>MidR)
   { MidR++;  }
   else// if(EndR>MidR)
   { MidR--;  }
   //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   if(MidG == StartG)
   { intG = 1;  }
   else if(StartG>MidG)
   { MidG++;  }
   else// if(EndG>MidG)
   { MidG--;  }
   //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   if(MidB == StartB)
   { intB = 1;  }
   else if(StartB>MidB)
   { MidB++;  }
   else// if(EndB>MidB)
   { MidB--;  }
  
   if(1 == intR && 1 == intB && 1 == intG)
   { return false;  }
   else
   { return true; }
  }
}

If you end up using this in any projects/work. I would love to hear. ^_^
... continue reading!