天天看點

Swing-鐘表 設計思路:

Swing-鐘表 設計思路:

 設計思路:

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);
	}
	
}
           

繼續閱讀