接着上面的部分,下面是APPLET主程序部分:
  
public class MyClock extends Applet implements Runnable {     static final int BACKGROUND=0;              //背景图片的序号,供数组使用     static final int LOGO=1;                    //LOGO图片的序号,供数组使用     static final String JAVEX="bear";          //表盘上显示的文字     static final double MINSEC=0.104719755;     //分针和秒针在表盘上的刻度(60个)间的弧度     static final double HOUR=0.523598776;       //时针在表盘上的刻度(24个)间的弧度 
    Thread clockThread = null; //使用多线程机制,用另一个线程不断显示图片 
    //提供的默认参数,如果HTML文件里面没有给参数就使用     int width = 100;     int height = 100;     Color bgColor = new Color(0,0,0);     Color faceColor = new Color(0,0,0);     Color sweepColor = new Color(255,0,0);     Color minuteColor = new Color (192,192,192);     Color hourColor = new Color (255,255,255);     Color textColor = new Color (255,255,255);     Color caseColor = new Color (0,0,0);     Color trimColor = new Color (192,192,192);     String logoString=null; 
    Image images[] = new Image[2]; //背景和LOGO的图片 
    boolean isPainted=false; //如果第一次载入时绘制背景及表盘,其他时候重绘则只绘制指针 
    //时钟圆心的位置     int x1,y1; 
    //最上面那个三角形的刻度图形的坐标     int xPoints[]=new int[3], yPoints[]=new int[3]; 
    //保存当前时间,转换成(double)(hours + minutes/60)     Hms cur_time; 
    //秒针、分针、时针     SweepHand sweep;     HmHand  minuteHand,             hourHand; 
    //用于绘制的时、分、秒     double lastHour;     int lastMinute,lastSecond; 
    //显示日期和表盘上的字母的字体     Font font; 
    //图片显示使用了缓冲机制,offScrImage和offScrGC存放缓冲区内图片的信息     Image offScrImage;     Graphics offScrGC; 
    //用于测试背景图片和LOGO图片     MediaTracker tracker; 
     int minDimension;   // 如果背景区域不是正方形的话,保证时钟在中间显示     int originX;        // 时钟图形所在正方形区域的左上角X坐标     int originY;        // 时钟图形所在正方形区域的左上角Y坐标 
    double tzDifference=0;  //时区间的差,向西为负数,向东为正数 
    boolean localOnly=false; //是否只使用本地时间,如果为FALSE则可以根据传入的时区显示该时区时间 
     //保存参数的类型说明     public String[][] getParameterInfo()     {         String[][] info = {             {"width",       "int",      "APPLET的长度,以象素为单位"},             {"height",      "int",      "APPLET的宽度,以象素为单位"},             {"bgColor",     "string",   "背景颜色,e.g FF0000"},             {"faceColor",   "string",   "表盘颜色"},             {"sweepColor",  "string",   "秒针颜色"},             {"minuteColor", "string",   "分针颜色"},             {"hourColor",   "string",   "时针颜色"},             {"textColor",   "string",   "文本颜色"},             {"caseColor",   "string",   "框内颜色"},             {"trimColor",   "string",   "空白区颜色"},             {"bgImageURL",  "string",   "背景图片地址"},             {"logoString",  "string",   "LOGO字符"},             {"logoImageURL","string",   "LOGO图片地址"},             {"timezone",    "real",     "时区间的差"},             {"localonly",   "int",      "是否考虑到时区差别"}         };         return info;     } 
    //显示信息     public String getAppletInfo()     {         return "版权所有,COPY必究,保护正版,人人有责";     } 
    void showURLerror(Exception e)      {         String errorMsg = "URL错误:"+e;         showStatus(errorMsg);         System.err.println(errorMsg);     } 
    //相当于把时钟变成100×100的大小,percent即相对坐标     private int size(int percent)     {         return (int)((double)percent/100.0 * (double)minDimension);     } 
    public void init()     {         URL imagesURL[] = new URL[2];         String szImagesURL[] = new String[2];         tracker = new MediaTracker(this);                  //得到HTML页面提供的参数,并把它转换相应的格式         String paramString    = getParameter( "WIDTH"  );         if( paramString != null )             width = Integer.valueOf(paramString).intValue(); 
        paramString   = getParameter( "HEIGHT" );         if( paramString != null )             height = Integer.valueOf(paramString).intValue(); 
       paramString   = getParameter( "TIMEZONE" );         if( paramString != null )             tzDifference = Double.valueOf(paramString).doubleValue(); 
       paramString  =   getParameter( "LOCALONLY" );         if( paramString != null && Integer.valueOf(paramString).intValue() != 0){                 localOnly=true;                 tzDifference=0.;         } 
        paramString    = getParameter( "BGCOLOR");         if( paramString != null )             bgColor=parseColorString(paramString); 
        paramString    = getParameter( "FACECOLOR");         if( paramString != null )             faceColor=parseColorString(paramString); 
        paramString    = getParameter( "SWEEPCOLOR");         if( paramString != null )             sweepColor=parseColorString(paramString); 
        paramString    = getParameter( "MINUTECOLOR");         if( paramString != null )             minuteColor=parseColorString(paramString); 
        paramString    = getParameter( "HOURCOLOR");         if( paramString != null )             hourColor=parseColorString(paramString); 
        paramString    = getParameter( "TEXTCOLOR");         if( paramString != null )             textColor=parseColorString(paramString); 
        paramString    = getParameter( "CASECOLOR");         if( paramString != null )             caseColor=parseColorString(paramString); 
        paramString    = getParameter( "TRIMCOLOR");         if( paramString != null )             trimColor=parseColorString(paramString); 
        logoString  = getParameter( "LOGOSTRING");         if( logoString == null )             logoString=JAVEX;         else if(logoString.length() > 8)             logoString= logoString.substring(0,8); //限制8个字母,否则显示不下! 
        //szImagesURL数组根据HTML传入参数存放图片的文件名         szImagesURL[BACKGROUND]  = getParameter("BGIMAGEURL");         szImagesURL[LOGO] = getParameter("LOGOIMAGEURL"); 
        //测试图片         for(int i=0; i<2; i++){             if(szImagesURL[i] != null){              //根据CodeBase参数与Image文件名得到image的路径,测试是否存在,如果不存在就不用图片                 try{                     imagesURL[i]=new URL(getCodeBase(),szImagesURL[i]);                  } catch (MalformedURLException e)                     {                         showURLerror(e);                         imagesURL[i]=null;                         images[i]=null;                     }                 if(imagesURL[i] != null){                     showStatus("加载图片: " + imagesURL[i].toString());                     images[i]=getImage(imagesURL[i]);                     if(images[i] != null)                         tracker.addImage(images[i],i);                     showStatus("");                 }                 try{                     tracker.waitForAll(i);                 }catch (InterruptedException e){}             }             else images[i]=null;         } 
        //得到相应时区的时间         cur_time=(localOnly)? new Hms() : new Hms(tzDifference);         lastHour=-1.0;         lastMinute=-1;         lastSecond=-1; 
        x1=width/2;         y1=height/2; 
        //换算出圆形时钟在背景里的左上角坐标         minDimension= Math.min(width, height);         originX=(width-minDimension)/2;         originY=(height-minDimension)/2; 
        //计算出上面三角形的三个点的坐标         xPoints[1]=x1-size(3); xPoints[2]=x1+size(3); xPoints[0]=x1;         yPoints[1]=y1-size(38);yPoints[2]=y1-size(38); yPoints[0]=y1-size(27); 
        //计算出秒针、分针、时针图形的各个点坐标         sweep=new SweepHand(x1,y1,size(40),3);         minuteHand=new HmHand(x1,y1,size(40),size(6),6);         hourHand=new HmHand(x1,y1,size(25),size(8),6); 
        //构造字体         font=new Font("TXT",Font.BOLD,size(10)); 
        //构造缓冲区内图形         offScrImage = createImage(width,height);         offScrGC = offScrImage.getGraphics(); 
        System.out.println(getAppletInfo());     } 
    public void start() //开始启动显示线程     {         if(clockThread == null){             clockThread = new Thread(this);         }         clockThread.start();             } 
    public void stop() //停止显示     {         clockThread = null;     } 
    private void drawHands(Graphics g)     { 
        double angle;         int i,j;         int x,y; 
        angle=MINSEC * lastSecond; //根据lastSecond算出秒针相对于12点刻度的角度         sweep.draw(faceColor, angle, g);//画出秒针 
        //如果时与分改变则重绘时针分针         if(cur_time.getMinutes() != lastMinute){             minuteHand.draw(faceColor,MINSEC*lastMinute,g);             if(cur_time.get_hours() != lastHour)                 hourHand.draw(faceColor,HOUR*lastHour,g);         } 
        g.setColor(textColor);         g.fillRect(originX+size(12),y1-size(2),size(10),size(4)); //绘制左侧横条         g.fillRect(x1-size(2),originY + minDimension-size(22),size(4),size(10)); //绘制下面的横条         g.fillPolygon( xPoints, yPoints, 3); //绘制顶部的三角形         for(i=1;i<12;i+=3) //在表盘的2、3、5、6、8、9、11时针刻度区绘制圆             for(j=i;j<i+2;j++){                 x=(int)(x1+Math.sin(HOUR*j)*size(35));                 y=(int)(y1-Math.cos(HOUR*j)*size(35));                 g.fillOval(x-size(3),y-size(3),size(6),size(6));             } 
        //设置字体         g.setFont(font);         FontMetrics fm=g.getFontMetrics(); 
        //画顶部的LOGO字符串         g.drawString(logoString,x1-fm.stringWidth(logoString)/2,y1-size(12)); 
        //得到日期         String day=Integer.toString(cur_time.getDate(),10); 
        //将日期绘制在表盘右侧         g.drawString(   day,                         originX + minDimension-size(14)-fm.stringWidth(day),                         y1+size(5)); 
        //外面画上框子         g.drawRect( originX + minDimension-size(14)-fm.stringWidth(day)-size(2),                     y1-size(5)-size(2),                     fm.stringWidth(day)+size(4),                     size(10)+size(4)); 
        if(images[LOGO] != null){ //如果LOGO图片存在,在底部画出来             x = originX + (minDimension-images[LOGO].getWidth(this))/2;             y = y1 + (minDimension/2 - size(22) - images[LOGO].getHeight(this))/2;             if(x > 0 && y > 0)                 offScrGC.drawImage(images[LOGO], x, y, this);         } 
        lastHour=cur_time.get_hours();         hourHand.draw(hourColor,HOUR*lastHour,g); //画时针 
        lastMinute=cur_time.getMinutes();         minuteHand.draw(minuteColor,MINSEC*lastMinute,g); //画分针 
        g.setColor(minuteColor); //绘制分针尾部的圆形         g.fillOval(x1-size(4),y1-size(4),size(8),size(8));         g.setColor(sweepColor); //绘制秒针尾部的圆形         g.fillOval(x1-size(3),y1-size(3),size(6),size(6)); 
        lastSecond=cur_time.getSeconds(); //得到新的秒数,重画         angle=MINSEC*lastSecond;         sweep.draw(sweepColor, angle,g); 
        g.setColor(trimColor);         g.fillOval(x1-size(1),y1-size(1),size(2),size(2)); //秒针尾部圆心部分应该是螺丝,挖空处理^_^     } 
    private Color parseColorString(String colorString) //参数传入为字符串形(规定为16进制6位字符串)     {         if(colorString.length()==6){             int R = Integer.valueOf(colorString.substring(0,2),16).intValue(); //前两位为R值             int G = Integer.valueOf(colorString.substring(2,4),16).intValue(); //中间为G值             int B = Integer.valueOf(colorString.substring(4,6),16).intValue(); //最后为B值             return new Color(R,G,B); //得到COLOR         }         else return Color.lightGray; //字符串不符合规范,默认为灰色     } 
    public void run()     {         repaint(); //每次启动时首先重绘一次         //每隔500ms获得现在时间并重绘一次         while(null != clockThread){             cur_time= (localOnly)? new Hms() :new Hms(tzDifference);             repaint(); 
            try{                 Thread.sleep(500);             } catch (InterruptedException e) {}         }     } 
    public void paint(Graphics g) //首先绘制缓冲区内图片,再显示出来     {         int i,x0,y0,x2,y2; 
        //如果没有提供背景图片,则用bgColor绘制背景         if(images[BACKGROUND] == null){             offScrGC.setColor(bgColor);             offScrGC.fillRect(0,0,width,height);         }         else //否则直接使用背景图片             offScrGC.drawImage(images[BACKGROUND], 0, 0, this); 
        //绘制外框到表盘间的部分         offScrGC.setColor(caseColor);  
        //将园形的范围适量缩减(不充满整个区域),防止有些地方被截取         offScrGC.fillOval(  originX+1,                             originY+1,                             minDimension-2,                             minDimension-2); 
        //绘制表盘         offScrGC.setColor(faceColor);         offScrGC.fillOval(  originX + size(5),                             originY + size(5),                             minDimension - size(10),                             minDimension - size(10)); 
        //绘制外框线         offScrGC.setColor(trimColor);         offScrGC.drawOval(  originX+1,                             originY+1,                             minDimension-2,                             minDimension-2); 
        //绘制内框线         offScrGC.drawOval(  originX + size(5),                             originY + size(5),                             minDimension - size(10),                             minDimension - size(10)); 
        offScrGC.setColor(textColor); 
        //画刻度,一共有60个刻度,x0、y0为刻度起始的位置,x1、y1圆心位置,x2、y2为刻度终止位置(x0<x2,y0<y2)         for(i=0;i<60;i++){             if(i==0 || (i>=5 && i%5 == 0)){ //每5格绘制一条长线(相对圆心)                 x0=(int)(x1+size(40)*Math.sin(MINSEC*i));                 y0=(int)(y1+size(40)*Math.cos(MINSEC*i));             }             else{ //其他部分绘制短线                 x0=(int)(x1+size(42)*Math.sin(MINSEC*i));                 y0=(int)(y1+size(42)*Math.cos(MINSEC*i));             }             x2=(int)(x1+size(44)*Math.sin(MINSEC*i));             y2=(int)(y1+size(44)*Math.cos(MINSEC*i));             offScrGC.drawLine(x0,y0,x2,y2);         } 
        drawHands(offScrGC); //绘制指针         g.drawImage(offScrImage,0,0,this); //把生成的缓冲区图形绘制到页面上 
        isPainted=true; //使下次UPDATE时不绘制表盘     } 
    public synchronized void update(Graphics g)     {         if(!isPainted)  //绘制表盘             paint(g);         else{    //已经绘制了表盘,只用绘制指针,首先在缓冲区内绘制,然后显示出来             drawHands(offScrGC);             g.drawImage(offScrImage,0,0,this);         }     } }
  
一个测试用的HTML的例子:
  
<HTML> <TITLE>我的时钟程序</TITLE> <BODY> <h2>显示东8区的时间</h2> <p> <applet code="MyClock.class" width="300" height="300">   <param name="BGCOLOR" value="FFFFFF">   <param name="FACECOLOR" value="FFFFFF">   <param name="SWEEPCOLOR" value="FF0000">   <param name="MINUTECOLOR" value="008080">   <param name="HOURCOLOR" value="000080">   <param name="TEXTCOLOR" value="000000">   <param name="CASECOLOR" value="000080">   <param name="TRIMCOLOR" value="C0C0C0">   <param name="LOGOIMAGEURL" value="java.gif">   <param name="TIMEZONE" value="8"> </p> </BODY> </HTML>  
 
  |