public void update(Graphics g) {
try {
//Получаем указатель на объект Graphics2D
Graphics2D g2 = (Graphics2D)g;
grawClock();
//Рисуем готовое изображение на экране
g2.drawImage(bi, 0, 0, this);
big.setTransform(new AffineTransform());
}
catch(Exception error) {
System.out.println(error.getMessage());
}
}
private void grawClock() {
//Узнаем текущее время
Calendar curTime = Calendar.getInstance();
curTime.setTimeInMillis(System.currentTimeMillis());
double hour = curTime.get(Calendar.HOUR_OF_DAY);
double min = curTime.get(Calendar.MINUTE);
double sec = curTime.get(Calendar.SECOND);
//Очищаем рисунок
big.setBackground(Color.WHITE);
big.clearRect(0, 0, w, h);
//Рисуем циферблат
Point luCorner = new Point(0, 0);
if(w > h)
{
luCorner.x = (w - h)/2;
luCorner.y = 0;
}
else
{
luCorner.x = 0;
luCorner.y = (h - w)/2;
}
big.drawImage(dial.getClockDial(), null, luCorner.x, luCorner.y);
//Рисуем стрелки
big.setColor(hoursColor);
AffineTransform hat = new AffineTransform();
hat.translate(w/2 - hNeedle.getRotationCenter().x,
h/2 - hNeedle.getRotationCenter().y);
/*Рассчитываем угол поворота часовой стелки. Каждый час на
12-ти часовом циферблате соответствует 30-ти градусам, а 1
минута - 0.5 градуса. Затем результат переводим в радианы. */
if(hour >= 12)
hour -= 12;
double theta = (-90 + (30*hour + 0.5*min))*Math.PI/180;
hat.rotate(theta, hNeedle.getRotationCenter().x,
hNeedle.getRotationCenter().y);
big.setTransform(hat);
big.fill(hNeedle.getNeedle());
big.setColor(minutesColor);
AffineTransform mat = new AffineTransform();
mat.translate(w/2 - mNeedle.getRotationCenter().x,
h/2 - mNeedle.getRotationCenter().y);
/*Рассчитываем угол поворота минутной стелки. Каждая минута на
12-ти часовом циферблате соответствует 6-ти градусам, а 1
секунда - 0.1 градуса. Затем результат переводим в радианы. */
theta = (-90 + (6*min + 0.1*sec))*Math.PI/180;
mat.rotate(theta, mNeedle.getRotationCenter().x,
mNeedle.getRotationCenter().y);
big.setTransform(mat);
big.fill(mNeedle.getNeedle());
big.setColor(secondsColor);
AffineTransform sat = new AffineTransform();
sat.translate(w/2 - sNeedle.getRotationCenter().x,
h/2 - sNeedle.getRotationCenter().y);
/*Рассчитываем угол поворота сеундной стелки. Каждая секунда на
12-ти часовом циферблате соответствует 6-ти градусам.
Затем результат переводим в радианы. */
theta = (-90 + (6*sec))*Math.PI/180;
sat.rotate(theta, sNeedle.getRotationCenter().x,
sNeedle.getRotationCenter().y);
big.setTransform(sat);
big.fill(sNeedle.getNeedle());
}
//Этот метод читает параметры апплета, и устанавливает
//цвета стрелок и циферблата.
privatevoidsetColors() {
try {
/* Вообще-то, для задания цвета нужно число типа int, т.е. 4 байта,
но int - это число со знаком (от "-2^31" до "2:31 - 1"), а нам
нужно число с диапазоном от "0" до "2^32", т.е. те же 4 байта,
но без знака. Для этого мы сначала создаем число типа Long, а
затем, с помощью метода intValue() получаем тип int.
*/
Long dc = new Long(Long.parseLong(getParameter("dialColor"), 16));
Long hlc = new Long(Long.parseLong(getParameter("hairLineColor"), 16));
Long hnc = new Long(Long.parseLong(getParameter("hoursNeedleColor"), 16));
Long mnc = new Long(Long.parseLong(getParameter("minutesNeedleColor"), 16));
Long snc = new Long(Long.parseLong(getParameter("secondsNeedleColor"), 16));
dialColor = new Color(dc.intValue(), true);
hairLineColor = new Color(hlc.intValue(), true);
hoursColor = new Color(hnc.intValue(), true);
minutesColor = new Color(mnc.intValue(), true);
secondsColor = new Color(snc.intValue(), true);
}
catch(Exception error) {
System.out.println(error.getMessage());
}
}
//Этот метод выполняется в отдельном потоке (timer).
//Он вызывает перерисовку окна апплета каждую секунду.
public void run() {
while(!stop) {
try {
repaint();
Thread.currentThread().sleep(1000);
}
catch(Exceptionerr) {}
}
}
//Этот метод выполняется если пользователь покинул страницу
//с апплетом. Он останавливает поток (timer) и, соответственно,
//перерисовку окна апплета.
publicvoidstop() {
super.stop();
stop = true;
}
//Этот метод выполняется когда пользователь попадает на страницу
//с апплетом. Он запускает парралельный поток (timer).
public void start() {
super.start();
stop = false;
if(timer == null) {
timer = new Thread(this);
timer.start();
}
}
//Этот метод выполняется при закрытии страницы с апплетом.
public void destroy() {
super.destroy();
stop = true;
//Ждем пока парралельный поток (timer) завершит работу.
Thread.currentThread().yield();
}
public String[][] getParameterInfo() {
String[][] retValue = {
{"dialColor", "hex", "alfa, red, green, blue (4 bytes, from 00 to FF)"},
{"hairLineColor", "hex", "alfa, red, green, blue (4 bytes, from 00 to FF)"},
{"hoursNeedleColor", "hex", "alfa, red, green, blue (4 bytes, from 00 to FF)"},
{"minutesNeedleColor", "hex", "alfa, red, green, blue (4 bytes, from 00 to FF)"},
{"secondsNeedleColor", "hex", "alfa, red, green, blue (4 bytes, from 00 to FF)"}
};
return retValue;
}
public String getAppletInfo() {
String retValue;
retValue = "Circle Clock";
return retValue;
}
}
// реализацияклассаClockDial
package clock;
/*
* ClockDial.java
*
* Created on май 2009 г.
*/
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
/**
*
* @author БочкареваМария
*/
public class ClockDial {
private double diam;
private BufferedImage dial;
private Color dialColor;
private Color hairLineColor;
/** Создаетэкземпляры <code>ClockDial</code>. При создании
* необходимо указать диаметр циферблата.
*
* @param diam диаметр циферблата.
*
* @param dialColor цвет циферблата.
*
* @param hairLineColor цвет черточек на циферблате.
*
* @exception IncorrectParametersException - если диаметр меньше
* или равен нулю.
*/
public ClockDial(double diam, Color dialColor, Color hairLineColor)
throws IncorrectParametersException {
//проверяемдиаметр
if(diam <= 0)
throw new IncorrectParametersException();
this.diam = diam;
this.dialColor = dialColor;
this.hairLineColor = hairLineColor;
//создаемрисунок
dial = new BufferedImage((int)diam, (int)diam,
BufferedImage.TYPE_INT_ARGB);
//создаемчерточкунациферблате
Rectangle2D.Double r = new Rectangle2D.Double(-diam/40, -diam/60, diam/20, diam/30);
AffineTransform at = new AffineTransform();
//смещаемначалокоординатвцентрциферблата
at.translate(diam/2, diam/2);
//сохраняем текущее преобразование
AffineTransform prev = (AffineTransform)at.clone();
//получаемграфическийконтекст
Graphics2D g2 = dial.createGraphics();
//закрашиваем все заданным цветом
g2.setBackground(dialColor);
g2.clearRect(0, 0, (int)diam, (int)diam);
//устанавливаемцветчерточек
g2.setColor(hairLineColor);
//рисуем 12 штрихов
for(int i = 0; i < 12; i++)
{
//смещаем центр координат к краю циферблата (туда,
//где должен быть расположен штрих)
at.translate(-(diam/2 - r.width), 0);
//поворачиваемштрихотносительноцентрациферблата
at.rotate(Math.toRadians(30*i), diam/2 - r.width, 0);
//устанавливаем текущее преобразование
g2.setTransform(at);
//рисуем штрих
g2.fill(r);
//восстанавливаем начальное преобразование
at.setTransform(prev);
}
}
/**
* Возвращает изображение циферблата.
*
* @return BufferedImage рисунок, содержащий изображение циферблата
*/
public BufferedImage getClockDial() {
return dial;
}
}
// реализациякласса IncorrectParametersException
package clock;
/*
* IncorrectParameters.java
*
* Created on май 2009 г.
* */
/**
*
* @author БочкареваМария
*/
public class IncorrectParametersException extends java.lang.Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>IncorrectParameters</code> without detail message.
*/
public IncorrectParametersException() {
this("IncorrectParameters");
}
/**
* Constructs an instance of <code>IncorrectParameters</code> with the specified detail message.
* @param msg the detail message.
*/
public IncorrectParametersException(String msg) {
super(msg);
}
}
// реализациякласса Needle
package clock;
/*
* Needle.java
*
* Created on май 2009 г.
*/
import java.awt.*;
import java.awt.geom.*;
/**
* Этот класс предназначен для создания стрелки часов
*
* @author БочкареваМария
*/
public class Needle {
private GeneralPath shape;
private double length, width;
/** Создает экземпляры класса <code>Needle</code>.
* При создании необходимо указать длину и ширину стрелки.
* Длина должна быть больше ширины.
*
* @param length длина стрелки
* @param width длина стрелки
*
* @exception IncorrectParametersException - если длина меньше или
* равна нулю, если ширина меньше или равна нулю, если длина
* меньшеилиравнаширине.
*/
public Needle(double length, double width)
throws IncorrectParametersException {
//проверяемпараметры
if(length <= 0 || width <=0 || length <= width)
throw new IncorrectParametersException();
this.length = length;
this.width = width;
//создаем графический объект
shape = new GeneralPath();
shape.moveTo(0f, (float)width/2);
shape.lineTo((float)width/2, 0);
shape.lineTo((float)length, (float)width/2);
shape.lineTo((float)width/2, (float)width);
shape.closePath();
}
/**
* Возвращает стрелку в виде объекта типа <code>Shape</code>.
* @return Shape - фигура, содержащая изображение стрелки
*/
public Shape getNeedle() {
return shape;
}
/**
* Возвращает центр вращения стрелки (точку, вокруг которой
* стрелка будет вращаться)
* @return Point2D.Double - точка, содержащая координаты центра вращения
* стрелки
*/
public Point2D.Double getRotationCenter() {
Point2D.Double rc = new Point2D.Double();
rc.x = rc.y = width/2;
return rc;
}
}