WELCOME CREDENTIALS NETCUENEWS NETCUELINKS EBIZ LINKS TIPS&TRICKS Y2K INFO

News Headlines Applet



This applet features a customizable background image and text messages that can be hyperlinked. Also notice that the message pauses when the mouse is over the applet.

The source code, html and helpful information are displayed below. Beyond that is a link to download the Fader.Class file.

/*------------------------------------------------------------------------------
News Headlines Applet

Copyright IBM Corporation 1997

Created by Bill Mueller of Eagle River Interactive, Inc for IBM February 1997.
Modified by Marc Goubert of IBM AlphaWorks June 1997 to:
- Add setting bgcolor and fontsize via PARAMs
- Add method translating RGB string to Color
Modified by John Graham 7/2/97 to:
- Headlines & their URLs now provided via PARAMs instead of a file to speed
applet startup time.
- A CGI script counts how many times a URL is accessed via the applet
- Headline area is nolonger hard coded. It is derived from applet size.
- Add support for multiple line headlines.
- Add locking to prevent thread problems.
- Desination URL now displayed in status area when mouse over headline
- Fade delay is now a param.
- Entire applet area is considered hot instead of just headline text area
Modified by Tafawa Kesler 3/20/98 to:
- Headlines fade from black to a specified background color.
- Add support for several font names (Helvetica, Courier, and TimesRoman)
- Add support for several font styles (Bold, Italic, and Plain)

An image file provides the background for this news headline display.
Each news headline is displayed, and then fades out to the next headline.

A mouse over a displayed headline will cause the headline to change color
and the destination URL to be displayed in the browser's status area.
Clicking on the headline will link to the news story.

This applet demonstrates the following techniques;
Displaying an image.
Creating a thread to loop through the display cycle
Using the MediaTracker to synchronize the image initialization.
Double buffering display image to eliminate flicker.
Fading a display image.
Using a CGI script on a seperate thread (implements a counter).

This applet intentionally tries to keep the number of classes to a minimum
to minimize the applet download time. This will not be as important once
JAR files are implemented by all browsers.

The following HTML example shows the Parameters that are supported by this
applet:

<body>

<applet code="fader.class" codebase="." width=150 height=60>
<!-- Area used to display headlines is based on applet width and height -->

<!-- Background image for headlines -->
<param name=image value="border3.gif">

<!-- Font size for headlines ... defaults to 12 -->
<param name=fontsize value="12">

<!-- Font name for headlines ... defaults to Helvetica. Choices also include
TimesRoman and Courier. -->
<param name=fontname value="Helvetica">

<!-- Font style for headlines ... defaults to Bold. Choices also include Plain,
Italic, or Bold+Italic. -->
<param name=fontstyle value="Bold">

<!-- RGB color for headlines -->
<param name=bgcolor value="#ffffff">

<!-- fadedelay for headlnes in milliseconds ... defaults to 25 -->
<param name=fadedelay value="25">

<!-- Each headline_ URL_ pair designate a headline to be displayed and
the URL to be jumped to when the user clicks on the headline .
The headline_ URL_ pairs start at 1 and go up until the first missing
headline_ or URL_ is detected -->
<param name=headline1 value="Free AS/400 toolbox for Java now available...">
<param name=URL1 value="http://www.ibm.com/java/sitenews/sitenews5.html">

<param name=headline2 value="New news on Java distributed computing...">
<param name=URL2 value="http://www.ibm.com/java/sitenews/sitenews4.html">

<param name=headline3 value="IBM announces open beta for JDK 1.1 for OS/2 Warp">
<param name=URL3 value="http://www.Internet.ibm.com/news/26e2.html">

</applet>


Known "Problems":
- It would be nice if the mouseDown, mouseEnter and mouseExit routines ignored
calls that happened after the browser has been told to goto a new URL. It is
easy to do this with a flag that is reset when start is driven after the
has returned to the page that contains the news applet. Unfortunately, if the
user never leaves the page that contains the news applet, start will not get
driven and there will be no way to get the fade loop going again.

------------------------------------------------------------------------------*/

import java.io.*;
import java.awt.*;
//import java.awt.image.*;
import java.applet.*;
import java.net.URL;
import java.net.*;
import java.util.*;
import java.lang.*;


/*------------------------------------------------------------------------------
Main Applet Class
----------------------------------------------------------------------------*/
public class fader extends Applet implements Runnable {
/* data for this applet */
private final int paramLow=1; // 1st PARAM is headline1 & URL is URL1
private int paramHigh; // last headline & URL PARAM
private String HeadlinesArray[]; // array of headline_ PARAMs
private String URLArray[]; // array of URL_ PARAMs
private int currentIndex = -1; // indexes HeadlinesArray & URLArray
private String currentHeadline = ""; // current headline displayed
private String currentURL = ""; // URL for current headline
private String hlArray[]; // currentHeadline broken into lines to display
private int hlArrayHigh; // highest used index of hlArray

private Image dBuffer; // Image for building display
private Graphics dGraphics; // Graphics for building display
private int applWidth, applHeight; // bounds of applet
private String bgFilename = "newsbg.gif"; // image for background
private String bgRGBcolor = "#ffffff"; // default background color string
private Color bgColor; // background color
private int fSize = 12; // default headline font size
private String fontName = "Helvetica"; // default headline font name
private int fontStyle = Font.BOLD; // default headline font style
private int fadedelay = 25; // default wait in each fade cycle
private Image bgImage; // image for background in display
final private int topPad=5; // top indention of headline area from appl bounds
final private int botPad=5; // bottom indention of headline area from appl bounds
final private int lftPad=5; // left indention of headline area from appl bounds
final private int rtPad=5; // right indention of headline area from appl bounds
private int maxTxtLines; // max # of lines in headline area
private int maxTxtLineLength; // max length of a headline area line
private Font headlineFont; // font used to print headlines
private FontMetrics headlineFontMetrics;// FontMetrics for headlineFont

private Thread timeThread = null; // thread for changing headline display
private boolean pauseDisplay = false; // don't update or fade headline
final private int numLoops = 200; // high bound for # of fade interations
private int valOpacity = 255; // used for fraction of RGB for fade
private int redValOpacity = 0;
private int greenValOpacity = 0;
private int blueValOpacity = 0;
final private int deltaOpacity = 5; // step decrement for valOpacity
private int redDeltaOpacity = 5;
private int greenDeltaOpacity = 5;
private int blueDeltaOpacity = 5;
private int redStart = 0;
private int greenStart = 0;
private int blueStart = 0;
private Color imageColor;
private long colorMask; // used to mask out RGB parts of fade
int mt=0; //jg?


private Frame parentFrame=null; // used to set mouse cursor


/*----------------------------------------------------------------------------
method to initialize applet
--------------------------------------------------------------------------*/
public void init()
{
String s; // temporary string
/* Get input parameters from HTML applet tag block */
bgFilename = getParameter("image");
s=getParameter("fontsize");
if (s != null) fSize = Integer.parseInt(s);
s = getParameter("fadedelay");
if (s != null) fadedelay = Integer.parseInt(s);

String t; // temporary string
t = getParameter("fontname");
if (t!= null) fontName = t;
t = getParameter("fontstyle");
if (t.equals("Plain")) fontStyle = Font.PLAIN;
if (t.equals("Italic")) fontStyle = Font.ITALIC;
if (t.equals("Bold+Italic")) fontStyle = Font.BOLD + Font.ITALIC;

bgRGBcolor = getParameter("bgcolor");
if (bgRGBcolor == null)
bgRGBcolor = "#000000";
bgColor = String2Color(bgRGBcolor);
// Load image and URL params.
String[] pa={"headline","URL"}; // prefixes of params
String[][] a=paramArray(pa,paramLow);
HeadlinesArray=a[0];
URLArray=a[1];
if (HeadlinesArray.length <= 0) {
System.err.println("No headline params. Terminating applet.");
showStatus("No headline params. Terminating applet.");
try {
wait();
} catch (InterruptedException e) {
System.err.println("Error occured in init for permanent wait");
e.printStackTrace();
};
}

/* Create Graphics double buffering */
applWidth = size().width;
applHeight = size().height;
dBuffer = createImage(applWidth, applHeight);
dGraphics = dBuffer.getGraphics();

/* Calculate the area for display of the headlines */
//headlineFont = new Font("Helvetica", Font.ITALIC, fSize);
headlineFont = new Font(fontName,fontStyle,fSize);
headlineFontMetrics = dGraphics.getFontMetrics(headlineFont);
maxTxtLines = (applHeight-topPad-botPad)/headlineFontMetrics.getHeight();
maxTxtLines = Math.max(maxTxtLines,1); // ensure we try at least 1 line
hlArray = new String[maxTxtLines];
int maxCharWidth = headlineFontMetrics.getMaxAdvance();
if ( maxCharWidth <= 0) maxCharWidth=headlineFontMetrics.charWidth('W');
maxTxtLineLength = applWidth-lftPad-rtPad;


/* load the background image */
bgImage = getImage(getCodeBase(), bgFilename);
MediaTracker trackit = new MediaTracker(this);
trackit.addImage(bgImage, 1);
try {
trackit.waitForAll();
} catch (InterruptedException e) {
System.err.println("Error occured in waitForAll for "+bgFilename);
e.printStackTrace();
}
if (trackit.isErrorID(1)) {
System.err.println("ErrorID in run reported error occured while loading "+
            bgFilename);
}
mt=1; //jg?

if (timeThread == null)
timeThread = new Thread(this);
//{{INIT_CONTROLS
        setLayout(null);
        addNotify();
        resize(430,270);
        //}}
colorMask = 0xffffff;

switchHeadline();

// Find Frame for applet...used to change mouse cursor
Component c = this;
while (!(c instanceof Frame)) c=c.getParent();
if (c != null) parentFrame=(Frame)c;
/*
int pixelArray[] = new int[applWidth*applHeight];
PixelGrabber g = new PixelGrabber(bgImage,0,0,applWidth,applHeight,pixelArray,0,applWidth);

try {
if (g.grabPixels()){
imageColor = new Color(pixelArray[0]);


}
} catch (InterruptedException e){
System.err.println("Error occurred in grabPixels for " + bgFilename);
e.printStackTrace();
}

// set up increment
if (bgFilename != "none"){
redStart = imageColor.getRed();
greenStart = imageColor.getGreen();
blueStart = imageColor.getBlue();
}
*/
redDeltaOpacity = (int)redStart/50;
greenDeltaOpacity = (int)greenStart/50;
blueDeltaOpacity = (int)blueStart/50;


} // end init()


/*----------------------------------------------------------------------------
Method to start timing thread. Called after init or when browser has
returned to the page containing the applet.
---------------------------------------------------------------------------*/
public void start()
{


if (timeThread != null)
timeThread.start(); // case were start called after init

if (timeThread == null)
{ // case were start called after stop
timeThread = new Thread(this);
timeThread.start();
}

} // end start()


/*----------------------------------------------------------------------------
Method to run thread in loop. Will be called as a result of calling
timeThread.start()
----------------------------------------------------------------------------*/
public void run()
{

Thread.currentThread().setPriority(Thread.NORM_PRIORITY-1); // main thread more important
int loopCtr = 0;

valOpacity = 0;
long time = System.currentTimeMillis();

/* Loop to display Headlines */
while (timeThread != null ) // stop will null timeThread & break loop
{
/* Pause loop processing */

try {
/* sleep so we will awake in 25 milliseconds */
time += fadedelay;
timeThread.sleep(Math.max(0,time - System.currentTimeMillis()));
} catch (InterruptedException e) {
System.err.println("Error occured in run for pause wait");
e.printStackTrace();
};

/* Check pause flag */
if (pauseDisplay)
continue; // mouse over headline
/* loop to display headlines */
loopCtr++;
if (loopCtr > numLoops)
{ // time to switch to next headline
loopCtr = 0;
switchHeadline();
redValOpacity = 0;
greenValOpacity = 0;
blueValOpacity = 0;
valOpacity = 0;
} else {
/* Fade out headline */
if (loopCtr > 120)
{
valOpacity = valOpacity + deltaOpacity;
redValOpacity = redValOpacity + redDeltaOpacity;
greenValOpacity = greenValOpacity + greenDeltaOpacity;
blueValOpacity = blueValOpacity + blueDeltaOpacity;
//if (valOpacity > 300)
//loopCtr= 999;
}
}
repaint();
}
timeThread = null;

} // end run()


/*----------------------------------------------------------------------------
method to stop applet when browser leaves page containing applet
----------------------------------------------------------------------------*/
public void stop()
{

timeThread.stop();
timeThread = null;

} // end stop()


/*----------------------------------------------------------------------------
Method to re-display applet ... called when applet starts & when
applet is exposed
----------------------------------------------------------------------------*/
public void paint(Graphics gr)
{
synchronized(dBuffer) { // prevent paint from seeing partially updated buffer
gr.drawImage(dBuffer, 0, 0, this);
} // end synchronized(dBuffer)

} // end paint(Graphics gr)


/*----------------------------------------------------------------------------
Update applet disply... driven by repaint()
----------------------------------------------------------------------------*/
public void update(Graphics gr)
{

synchronized(dBuffer) { // prevent paint from seeing partially updated buffer
/* fill applet with background color */
dGraphics.setColor(bgColor);

dGraphics.fillRect(0,0,applWidth,applHeight);
       
/* Draw Background Image */
boolean tb=dGraphics.drawImage(bgImage,0,0,applWidth,applHeight,this);


/* Calculate the headline color with current opacity */
int r = Math.min(255, (int)(((colorMask&0xff0000)>>16) * redValOpacity)/400);
int g = Math.min(255, (int)(((colorMask&0x00ff00)>>8) * greenValOpacity)/400);
int b = Math.min(255, (int)((colorMask&0x0000ff) * blueValOpacity)/400);

/* Draw Headline */
int stringY = topPad+headlineFontMetrics.getAscent(); // y position to drawString
dGraphics.setColor(new Color( r, g, b ));
dGraphics.setFont(headlineFont);
for(int j = 0; j <= hlArrayHigh; j++){

dGraphics.drawString(hlArray[j], lftPad, stringY);
stringY += headlineFontMetrics.getHeight(); // new y position for drawString
}

gr.drawImage(dBuffer, 0, 0, this); // display image
} // end synchronized(dBuffer)

} // end update(Graphics gr)


/*----------------------------------------------------------------------------
Convert RRGGBB string to color. Allows the user to use the HTML style
specification starting with a # or the # can be left off
----------------------------------------------------------------------------*/
public Color String2Color(String s)
{

String retcolor;
Color myColor;

if(s == null)
return null;
if(s.charAt(0) == '#') {
// string starts with #...jump over it
char chars[];
chars = new char [s.length()];
s.getChars(0, s.length(), chars, 0);
myColor = new Color(Integer.parseInt(new String(chars, 1, s.length()-1), 16));
redStart = myColor.getRed();
greenStart = myColor.getGreen();
blueStart = myColor.getBlue();
return(myColor);
} else {
myColor = new Color(Integer.parseInt(s, 16));
redStart = myColor.getRed();
greenStart = myColor.getGreen();
blueStart = myColor.getBlue();
return(myColor);
}
} // end String2Color(String s)


/*----------------------------------------------------------------------------
Method to catch the mouse button being pushed down. Since run may
call switchHeadline on a different thread, there is a small chance
the URL may not match the current headline. If this becomes a
problem it could be fixed by locking.
----------------------------------------------------------------------------*/
public boolean mouseDown( Event event, int x, int y)
{
pauseDisplay = true; // keep run from updating display

/* Link to headline */
URL url_ = null;
try { url_ = new
URL(getCodeBase(), currentURL ); }
catch (Exception e) { }
AppletContext ac = getAppletContext();
ac.showDocument(url_,"_blank"); // browser to show currentURL asynchronously

return true;
} // end mouseDown( Event event, int x, int y)


/*----------------------------------------------------------------------------
Method to called when the mouse enters the applet.

Since run may call switchHeadline on a different thread, there is a
small chance the URL may not match the current headline. If this
becomes a problem it could be fixed by locking. switchHeadline checks for
a paused display to minimize the chance of undesireable switches.

A race condition is also possible on valOpacity with run, however, the logic
flow makes so the race won't result in user preceivable errors.
----------------------------------------------------------------------------*/
public boolean mouseEnter( Event event, int x, int y)
{
pauseDisplay = true; // keep run from updating the display

parentFrame.setCursor(java.awt.Frame.HAND_CURSOR);
showStatus(currentURL); // print destination URL in status area
colorMask = 0xffff00; // display will not contain B in it's color
valOpacity = 0; // set to original "full" value
redValOpacity = 0;
greenValOpacity = 0;
blueValOpacity = 0;
repaint(); // update display with new headline color

return true;
} // end mouseEnter( Event event, int x, int y)


/*----------------------------------------------------------------------------
Called when mouse has left the applet
----------------------------------------------------------------------------*/
public boolean mouseExit( Event event, int x, int y)
{

parentFrame.setCursor(java.awt.Frame.DEFAULT_CURSOR);
showStatus(""); // clear old destination URL in status area
colorMask = 0xffffff; // headline display should use B
valOpacity = 0; // set to original "full" value
redValOpacity = 0;
greenValOpacity = 0;
blueValOpacity = 0;
repaint(); // update display with new headline color
pauseDisplay = false; // allow run to update the display

return true;
} // end mouseExit( Event event, int x, int y)


/*----------------------------------------------------------------------------
Switch to next headline
----------------------------------------------------------------------------*/
private void switchHeadline() {

if (pauseDisplay) {

return; // ignore any spurious switch calls while display paused
}
if ( ++currentIndex >= HeadlinesArray.length) currentIndex = 0;
currentHeadline = HeadlinesArray[currentIndex];
currentURL = URLArray[currentIndex];

/* break headline into lines for display in headline area */
synchronized(dBuffer) {
// locks on image buffer to prevent update from seeing an
// incomplete hlArray. Could have locked on hlArray for better
// lock resolution, but that would have made update have to get
// and release hlArray as well as dBuffer.
StringTokenizer tokens = new StringTokenizer(currentHeadline);
for (int i=0; i<hlArray.length; i++) {hlArray[i]="";} // null out old lines
int i = 0;
String oldString;
String nToken;
hlArrayHigh = 0; // highest line we have filled in so far
parseHL: while (tokens.hasMoreTokens()) {
nToken = tokens.nextToken();
oldString = hlArray[i];
// add new token to current line
if ((hlArray[i]).length() != 0) hlArray[i] = hlArray[i] + " " + nToken;
else hlArray[i] = nToken;

if (headlineFontMetrics.stringWidth(hlArray[i]) > maxTxtLineLength) {
// line too long with new token
if (oldString == "")
continue; // new token only word on line...let drawString truncate it
else {
hlArray[i] = oldString; // restore line prior to it being too long
if (++i >= hlArray.length) break parseHL; // out of display lines...quit
hlArray[i] = nToken; // use new token on next line
hlArrayHigh = i; // highest line we have filled in so far
}
}
}
} // end synchronized(dBuffer)

} // end switchHeadline()


/*----------------------------------------------------------------------------
For each element of passed array paramPrefixes, return an array in the
2 dimension array that contains the values of each param starting with
the prefix. For example, if paramPrefixes={"image","URL"}, paramLow=1
and the params on the applet tag are image1=a, image2=b, url1=c, and
url2=d, the returned array will be as follows: {{a,b},{c,d}}

The params specified by paramPrefixes are considered to start with
a suffix of paramLow and to increase sequentially. The first missing suffix
signals the end of the params for that prefix.

All of the params specified by paramPrefixes are considered to be a matched
set, so it is an error if for a given suffix, params exist for some of the
prefixes but not for the others. When this error occurs, a message is
printed on stderr, but processing continues.

Note that all the arrays used here have 0 as their first index, regardless
of what the value of paramLow is.
---------------------------------------------------------------------------*/
private String[][] paramArray(String[] paramPrefixes, //prefixes of params
int paramLow //first suffix
) {
// each vector in v will hold values for a prefix
Vector[] v=new Vector[paramPrefixes.length];
for (int i=0;i<paramPrefixes.length;i++) {v[i]=new Vector();}
String[] paramValues=new String[paramPrefixes.length];
scanparams: for (int i=paramLow; ;i++) { // suffix we are trying
for (int j=0; j<paramPrefixes.length; j++) { // try each prefix for suffix
paramValues[j]=getParameter(paramPrefixes[j]+i);
}
// see if 1 prefix, all prefixes, or no prefixes got a value for this suffix
boolean got1Parm=false;
boolean gotAllParm=true;
for (int j=0; j<paramPrefixes.length; j++) {
if (paramValues[j] !=null) {
got1Parm=true;
}
else {
gotAllParm=false;
}
}
if (got1Parm) // 1 prefix got a value
if (gotAllParm) // all prefixes got a value
// add each value to vector holding values for the prefix
for (int j=0; j<paramPrefixes.length; j++) {
String x=paramValues[j];
v[j].addElement(x);
}
else { // only some prefixes got a value
// warn user which prefixes were missing a value
for (int j=0; j<paramPrefixes.length; j++) {
if (paramValues[j] == null)
System.err.println("Missing param " + paramPrefixes[j]+i +"\n");
}
break scanparams; // stop checking for params
}
else { // no prefixes had a value...this is the end
break scanparams; // stop checking for params
}
}

// copy values for each prefix into the 2 dim array we return
String[][]params = new String[paramPrefixes.length][v[0].size()];
for (int j=0; j<paramPrefixes.length; j++) {
v[j].copyInto(params[j]);
}
return params;
} // end paramArray(String[] paramPrefixes, int paramLow)


/* define Applet Information string */
public String getAppletInfo()
{
return "IBM Headlines Applet. Copyright IBM 1997";
} // end getAppletInfo()

    //{{DECLARE_CONTROLS
    //}}
} // end of applet class


Download Fader.Class File


Return to Netcue Tips & Tricks>>