import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.util.Calendar; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities;@SuppressWarnings("serial") public class ClockExample extends JFrame { private ClockPanel clockPanel; private Date date = new Date(); public ClockExample() { super("Analog Clock"); final Container container = getContentPane(); clockPanel = new ClockPanel(); container.add(clockPanel, BorderLayout.CENTER); pack(); setDefaultCloseOperation(EXIT_ON_CLOSE); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { @Override public void run() { final long time = date.getTime(); date = new Date(time + 1000); clockPanel.setTime(date); } }, 1, 1, TimeUnit.SECONDS); setVisible(true); } public static void main(final String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new ClockExample(); } }); }}// //////////////////////////////////////////////////////////////Clock class class ClockPanel extends JPanel { private static final long serialVersionUID = 111111111111L; private static final double TWO_PI = 2.0 * Math.PI; private Calendar _now = Calendar.getInstance(); // Current time. private int _diameter; // Height and width of clock face private int _centerX; // x coord of middle of clock private int _centerY; // y coord of middle of clock private BufferedImage _clockImage; // Saved image of the clock face. // ==================================================== Clock constructor public ClockPanel() { setPreferredSize(new Dimension(300, 300)); } // =========================================================== updateTime void setTime(final Date date) { // ... Avoid creating new objects. _now.setTime(date); repaint(); } // ======================================================= paintComponent @Override public void paintComponent(final Graphics g) { final Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke(2.f)); // ... The panel may have been resized, get current dimensions final int w = getWidth(); final int h = getHeight(); _diameter = ((w < h) ? w : h); _centerX = _diameter / 2; _centerY = _diameter / 2; // ... Create the clock face background image if this is the first time, // or if the size of the panel has changed if (_clockImage == null || _clockImage.getWidth() != w || _clockImage.getHeight() != h) { _clockImage = (BufferedImage) (this.createImage(w, h)); // ... Get a graphics context from this image final Graphics2D g2a = _clockImage.createGraphics(); g2a.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawClockFace(g2a); } // ... Draw the clock face from the precomputed image g2.drawImage(_clockImage, null, 0, 0); // ... Draw the clock hands dynamically each time. drawClockHands(g2); } // ====================================== convenience method drawClockHands private void drawClockHands(final Graphics2D g2) { // ... Get the various time elements from the Calendar object. final int hours = _now.get(Calendar.HOUR); final int minutes = _now.get(Calendar.MINUTE); final int seconds = _now.get(Calendar.SECOND); final int millis = _now.get(Calendar.MILLISECOND); // ... second hand @SuppressWarnings("unused") int handMin = _diameter / 8; // Second hand doesn't start in middle. int handMax = _diameter / 2 - 20; // Second hand extends to outer rim. final double fseconds = (seconds + (double) millis / 1000) / 60.0; drawRadius(g2, fseconds, 0, handMax); // ... minute hand handMin = 0; // Minute hand starts in middle. handMax = _diameter / 3 - 5; final double fminutes = (minutes + fseconds) / 60.0; drawRadius(g2, fminutes, 0, handMax); // ... hour hand handMin = 0; handMax = _diameter / 4; drawRadius(g2, (hours + fminutes) / 12.0, 0, handMax); } // ======================================= convenience method drawClockFace private void drawClockFace(final Graphics2D g2) { // ... Draw the clock face. Probably into a buffer. g2.setColor(Color.PINK); g2.fillOval(0, 0, _diameter, _diameter); g2.setColor(Color.BLACK); g2.drawOval(0, 0, _diameter, _diameter); g2.fillOval(_centerX - 4, _centerY - 4, 8, 8); final int radius = _diameter / 2; // g2.drawString("12", 145, 25); // g2.drawString("6",150,275); // g2.drawString("9",25,146); // g2.drawString("3",275,146); // ... Draw the tick s around the circumference. for (int sec = 0; sec < 60; sec++) { int tickStart; if (sec % 5 == 0) { tickStart = radius - 10; // Draw long tick every 5. } else { tickStart = radius - 5; // Short tick . } drawRadius(g2, sec / 60.0, tickStart, radius); } } // ==================================== convenience method drawRadius // This draw lines along a radius from the clock face center. // By changing the parameters, it can be used to draw tick s, // as well as the hands. private void drawRadius(final Graphics2D g2, final double percent, final int minRadius, final int maxRadius) { // ... percent parameter is the fraction (0.0 - 1.0) of the way // clockwise from 12. Because the Graphics2D methods use radians // counterclockwise from 3, a little conversion is necessary. // It took a little experimentation to get this right. final double radians = (0.5 - percent) * TWO_PI; final double sine = Math.sin(radians); final double cosine = Math.cos(radians); final int dxmin = _centerX + (int) (minRadius * sine); final int dymin = _centerY + (int) (minRadius * cosine); final int dxmax = _centerX + (int) (maxRadius * sine); final int dymax = _centerY + (int) (maxRadius * cosine); g2.drawLine(dxmin, dymin, dxmax, dymax); } }
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;@SuppressWarnings("serial")
public class ClockExample extends JFrame {
private ClockPanel clockPanel;
private Date date = new Date(); public ClockExample() {
super("Analog Clock");
final Container container = getContentPane();
clockPanel = new ClockPanel();
container.add(clockPanel, BorderLayout.CENTER);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
final long time = date.getTime();
date = new Date(time + 1000);
clockPanel.setTime(date);
}
}, 1, 1, TimeUnit.SECONDS);
setVisible(true);
} public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ClockExample();
}
});
}}// //////////////////////////////////////////////////////////////Clock class
class ClockPanel extends JPanel {
private static final long serialVersionUID = 111111111111L;
private static final double TWO_PI = 2.0 * Math.PI; private Calendar _now = Calendar.getInstance(); // Current time. private int _diameter; // Height and width of clock face
private int _centerX; // x coord of middle of clock
private int _centerY; // y coord of middle of clock
private BufferedImage _clockImage; // Saved image of the clock face. // ==================================================== Clock constructor
public ClockPanel() {
setPreferredSize(new Dimension(300, 300));
} // =========================================================== updateTime
void setTime(final Date date) {
// ... Avoid creating new objects.
_now.setTime(date);
repaint();
} // ======================================================= paintComponent
@Override
public void paintComponent(final Graphics g) {
final Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke(2.f));
// ... The panel may have been resized, get current dimensions
final int w = getWidth();
final int h = getHeight();
_diameter = ((w < h) ? w : h);
_centerX = _diameter / 2;
_centerY = _diameter / 2; // ... Create the clock face background image if this is the first time,
// or if the size of the panel has changed
if (_clockImage == null || _clockImage.getWidth() != w || _clockImage.getHeight() != h) {
_clockImage = (BufferedImage) (this.createImage(w, h)); // ... Get a graphics context from this image
final Graphics2D g2a = _clockImage.createGraphics();
g2a.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawClockFace(g2a);
} // ... Draw the clock face from the precomputed image
g2.drawImage(_clockImage, null, 0, 0); // ... Draw the clock hands dynamically each time.
drawClockHands(g2);
} // ====================================== convenience method drawClockHands
private void drawClockHands(final Graphics2D g2) {
// ... Get the various time elements from the Calendar object.
final int hours = _now.get(Calendar.HOUR);
final int minutes = _now.get(Calendar.MINUTE);
final int seconds = _now.get(Calendar.SECOND);
final int millis = _now.get(Calendar.MILLISECOND); // ... second hand
@SuppressWarnings("unused")
int handMin = _diameter / 8; // Second hand doesn't start in middle.
int handMax = _diameter / 2 - 20; // Second hand extends to outer rim.
final double fseconds = (seconds + (double) millis / 1000) / 60.0;
drawRadius(g2, fseconds, 0, handMax); // ... minute hand
handMin = 0; // Minute hand starts in middle.
handMax = _diameter / 3 - 5;
final double fminutes = (minutes + fseconds) / 60.0;
drawRadius(g2, fminutes, 0, handMax); // ... hour hand
handMin = 0;
handMax = _diameter / 4;
drawRadius(g2, (hours + fminutes) / 12.0, 0, handMax);
} // ======================================= convenience method drawClockFace
private void drawClockFace(final Graphics2D g2) {
// ... Draw the clock face. Probably into a buffer.
g2.setColor(Color.PINK);
g2.fillOval(0, 0, _diameter, _diameter);
g2.setColor(Color.BLACK);
g2.drawOval(0, 0, _diameter, _diameter);
g2.fillOval(_centerX - 4, _centerY - 4, 8, 8); final int radius = _diameter / 2; // g2.drawString("12", 145, 25);
// g2.drawString("6",150,275);
// g2.drawString("9",25,146);
// g2.drawString("3",275,146); // ... Draw the tick s around the circumference.
for (int sec = 0; sec < 60; sec++) {
int tickStart;
if (sec % 5 == 0) {
tickStart = radius - 10; // Draw long tick every 5.
} else {
tickStart = radius - 5; // Short tick .
}
drawRadius(g2, sec / 60.0, tickStart, radius);
}
} // ==================================== convenience method drawRadius
// This draw lines along a radius from the clock face center.
// By changing the parameters, it can be used to draw tick s,
// as well as the hands.
private void drawRadius(final Graphics2D g2, final double percent, final int minRadius, final int maxRadius) {
// ... percent parameter is the fraction (0.0 - 1.0) of the way
// clockwise from 12. Because the Graphics2D methods use radians
// counterclockwise from 3, a little conversion is necessary.
// It took a little experimentation to get this right.
final double radians = (0.5 - percent) * TWO_PI;
final double sine = Math.sin(radians);
final double cosine = Math.cos(radians); final int dxmin = _centerX + (int) (minRadius * sine);
final int dymin = _centerY + (int) (minRadius * cosine); final int dxmax = _centerX + (int) (maxRadius * sine);
final int dymax = _centerY + (int) (maxRadius * cosine);
g2.drawLine(dxmin, dymin, dxmax, dymax);
}
}