![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TUPhXSU5kerp3YxRmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4ETM3ADOxATMwEDOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
設計思路:
1、‘開始’監聽器的設計
定義一個swing 下的Timer對象,每隔一段時間,觸發一次timer的監聽器(重新繪制鐘表面闆),即令鐘表可以走動
2、鐘表的設計
難點在于鐘表角度的繪制,
在這裡為鐘表加上了一個輻射漸變背景圖
詳情見代碼注釋:
3、‘停止’按鈕的設計
即timer.stop();
三個類:
1、鐘表面闆設計類
2、注面闆設計類
3、main類
package my3;
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Swing2
{
private static void createGUI()
{
// JFrame指一個視窗,構造方法的參數為視窗标題
// 文法:因為MyFrame是JFrame的子類,是以可以這麼寫
JFrame frame = new MyFrame("Js鐘表");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 設定視窗的其他參數,如視窗大小
frame.setSize(700, 450);
// 顯示視窗
frame.setVisible(true);
}
public static void main(String[] args)
{
// 此段代碼間接地調用了 createGUI()
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run()
{
createGUI();
}
});
}
}
package my3;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class MyFrame extends JFrame
{
CustomClock clock=new CustomClock();
Timer timer;
public MyFrame(String title)
{
super(title);
// Content Pane
JPanel root = new JPanel();
this.setContentPane(root);
root.setLayout(new BorderLayout());
root.add(clock, BorderLayout.CENTER);
// 工具欄
Box toolbar = Box.createHorizontalBox();
JButton startButton = new JButton("開始");
JButton stopButton = new JButton("停止");
toolbar.add(startButton);
toolbar.add(Box.createHorizontalStrut(10));
toolbar.add(stopButton);
root.add(toolbar, BorderLayout.PAGE_START);
startButton.addActionListener( (e)->{
startClock();
});
stopButton.addActionListener( (e)->{
stopClock();
});
}
private void startClock()
{
if(timer!=null) return;
//建立定時器,每隔1000毫秒執行一次
//第一個參數是delay
//第二個參數為ActionListener,可以用匿名類或者Lamada表達式
// timer=new Timer(1000,(e)-> {
// clock.repaint(); //重置時鐘
// });
//匿名類
timer=new Timer(1000,new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clock.repaint();
}
});
timer.start();
}
private void stopClock()
{
if(timer != null)
{
timer.stop();
timer = null;
}
}
}
package my3;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Calendar;
import javax.swing.JPanel;
public class CustomClock extends JPanel
{
@Override
protected void paintComponent(Graphics g)
{
int width=this.getWidth();
int height=this.getHeight();
Graphics2D g2d=(Graphics2D)g;
// 平滑繪制 ( 反鋸齒 )
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.white);
g2d.fillRect(0, 0, width, height);
// 取得一個最大的正文形
//Rectangle rect = new Rectangle(0,0,200,200);
int w = width;
int h = width;
if( h > height)
{
h = height;
w = height;
}
Rectangle rect = new Rectangle((width-w)/2, (height-h)/2, w, h);
rect.grow(-4,-4); // 往裡縮一點
//中心點以及半徑
int centerX=(int)rect.getCenterX();
int centerY=(int)rect.getCenterY();
int radius=(int)rect.width/2;
//表盤的圓框 /
if(true)
{
// 背景填充白色
// g2d.setPaint(new Color(0xFFFFFF));
// g2d.fillOval(rect.x, rect.y, rect.width, rect.height);
// 邊框
g2d.setStroke(new BasicStroke(4));
g2d.setPaint(Color.RED);
g2d.drawOval(rect.x, rect.y, rect.width, rect.height);
}
/// 刻度 /
if(true)
{
g2d.setStroke(new BasicStroke(4));
for(double angle=0;angle<360;angle+=30)
{
drawRadialLine(g2d, centerX, centerY, radius, angle);
}
//截斷輻條得到刻度
radius-=5;
// g2d.setPaint(Color.WHITE);
// g2d.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
//中心畫一個小圓點
int r=4;
g2d.setPaint(Color.RED);
g2d.fillOval(centerX-r, centerY-r, r*2, r*2);
}
//輻射漸變填充
if(true)
{
Point2D center=new Point2D.Double(centerX,centerY);
float[] dist= {0.0f,0.2f,1.0f}; //距離
Color[] colors = { Color.RED, Color.WHITE, Color.BLUE }; //顔色
//Gradient 梯度
RadialGradientPaint paint=new RadialGradientPaint(center,radius,dist,colors);
g2d.setPaint(paint);
g2d.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
}
//秒針,分針,時針 ///
//得到時分秒值
Calendar cal=Calendar.getInstance();
int hour=cal.get(Calendar.HOUR);
int minute=cal.get(Calendar.MINUTE);
int second=cal.get(Calendar.SECOND);
//時針
if(true)
{
double radius2=radius*0.5;
g2d.setPaint(Color.ORANGE);
g2d.setStroke(new BasicStroke(6));
//計算角度
double vv=hour+minute/60.0;
drawRadialLine(g2d,centerX,centerY,radius2,vv/12.0*360-90);
}
// 分針
if(true)
{
double radius2 = radius *0.7;
g2d.setPaint(Color.GREEN);
g2d.setStroke(new BasicStroke(3));
double vv = minute + second/60.0; // 角度計算有一點點複雜
drawRadialLine(g2d, centerX, centerY, radius2, minute/60.0 * 360 - 90);
}
// 秒針
if(true)
{
double radius2 = radius *0.9;
g2d.setPaint(Color.RED);
g2d.setStroke(new BasicStroke(1));
drawRadialLine(g2d, centerX, centerY, radius2, second/60.0 * 360 - 90 );
}
}
// 繪制從圓心發散出的輻條線條,中心centerX, centerY, 半徑radius, 角度angle
private void drawRadialLine(Graphics2D g2d,
double centerX, double centerY,
double radius, double angle)
{
double radian=angle/180*Math.PI; //角度轉化為弧度
double x = centerX + radius * Math.cos( radian );
double y = centerY + radius * Math.sin( radian );
Line2D line=new Line2D.Double(x, y, centerX, centerY);
g2d.draw(line);
}
}