java可视化编程实践--桌面时钟

定义六个类用于实现整个可视化时钟
Clock.java:时钟类,聚合表盘和3个指针对象,构成整个时钟

Plate.java:表盘类,用来显示静态的时钟表盘、刻度等内容

Arm.java:指针类,用来显示时、分、秒指针

ClockComponent:可视化时钟组件类,时钟的可视化显示,即整个时钟界面的表盘显示。

ClockFrame:整个程序窗口类,用于显示整个程序的窗口。

VisualClock:主程序类,用于程序的启动。

主要的程序如下:

VisualClock:

import java.awt.EventQueue;
import javax.swing.JFrame;
/*顶层窗口 JFrame 内容区域包括 2 个部分,上方为时钟的可视化显示,下方
为文本显示,上方用 JComponent 组件实现,在其 paintComponent 方法中绘制,
下方用 JLabel 实现,可以采用 BorderLayout 布局实现
*/

//添加主程序类
public class VisualClock {
	public static void main(String[] args) {
		EventQueue.invokeLater(()->{
			ClockFrame frame=new ClockFrame();
			frame.setTitle("可视化时钟");
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
			frame.setVisible(true);
			});
	}
}

ClockFrame:

import java.awt.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import javax.swing.*;
import java.util.Date;
//创建顶层窗口类
public class ClockFrame extends JFrame {
	private ClockComponent comp;//整个时钟的显示
	private JLabel timeLabel;//时钟的文本显示
	public ClockFrame() {
		setSize(500,400);
		setLayout(new BorderLayout());
		comp=new ClockComponent();
		add(comp, BorderLayout.CENTER);
		JPanel timeLabelPanel=new JPanel();
		timeLabel=new JLabel(""+new Date());
		timeLabelPanel.add(timeLabel);
		add(timeLabelPanel, BorderLayout.SOUTH);
		//创建定时器并通过start启动定时器,每隔一秒根据当前系统生成的时间
		//生成字符串,将字符串更新到timeLabel上,同时调用repaint方法刷新comp显示
		new Timer(1000,event->{
			Date date=new Date();
			DateFormat format=new SimpleDateFormat(
			     "yyyy-MM-dd HH:mm:ss");
			     String time=format.format(date);
			     timeLabel.setText(time);
			     comp.repaint();
			}).start();
	}
}

ClockComponent:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
//添加可视化时钟组件类
public class ClockComponent extends JComponent {
	//时钟的可视化显示,即整个时钟界面的表盘显示
	Clock clock,clock1;
	public ClockComponent(){
		clock=new Clock();
		clock1=new Clock();
	}
	public void paintComponent(Graphics g){
		Rectangle2D r=getBounds();
	     Graphics2D g2=(Graphics2D)g;
	     clock.setRectangle(new Rectangle2D.Double(r.getX(),r.getY(),r.getWidth()/2,r.getHeight()));//通过 getBounds 方法获得组件窗体的大小,并将期传给 clock 对象,再间接传递给 plate 对象
	     clock1.setRectangle(new Rectangle2D.Double(r.getWidth()/2,r.getY(),r.getWidth()/2,r.getHeight()));
	     
	     clock.draw(g2);//Graphics2D对象也是由 clock 的 draw 方法传递给 plate 的 draw 方法,从而将表盘绘制在Component 组件中。
	     clock1.draw1(g2);
	}
}

Clock:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
public class Clock {
	//时钟类,聚合表盘和3个指针对象,构成整个时钟
	private Plate plate;
	private Arm hour,minute,second;
	
	public Clock(){
		plate=new Plate();//构造表盘对象
		//调用指针的创建与绘制
		hour=new Arm(Arm.Type.HOUR);
		minute=new Arm(Arm.Type.MINUTE);
		second=new Arm(Arm.Type.SECOND);
		hour.setColor(Color.red);
		minute.setColor(Color.BLUE);
		second.setColor(Color.green);
		
	}
	
	public void setRectangle(Rectangle2D rect){
		plate.setRectangle(rect);//设置外界矩形大小
		//plate.setRectangle(rect);
		hour.setRectangle(rect);
		minute.setRectangle(rect);
		second.setRectangle(rect);
	}
	
	public void draw(Graphics2D g2){
		plate.draw(g2);//绘制表盘
		hour.draw(g2);
		minute.draw(g2);
		second.draw(g2);
	}
	public void draw1(Graphics2D g2){
		plate.draw(g2);//绘制表盘
		hour.draw1(g2);
		minute.draw1(g2);
		second.draw1(g2);
	}
}

Plate:

import java.awt.*;
import java.awt.geom.*;
public class Plate {
	//表盘类,用来显示静态的时钟表盘、刻度等内容
	public static final int LINE_LENGTH=9; //刻度长度
	public static final float LINE_WIDTH=3.0f; //线宽
	public static final int GAP=10; //保留和边界的距离
	private Color backgroundColor=Color.LIGHT_GRAY;
	private Color lineColor=Color.BLACK;
	private Color numColor=Color.RED; //不同对象的颜色
	private Rectangle2D r; //控制表盘大小的外接矩形
	
	void setRectangle(Rectangle2D rect){
		r=rect;
	}
	/*
	 Plate 类封装了对表盘的绘制,通过 draw 接口,将表盘绘制在传入的
     Graphics2D 对象上,由于 Plate 本身无法确定表盘的大小,需要从外部设置外接
         矩形的参数。在程序运行过程中,窗口大小发生变化时,需要调用 setRectangle
         接口重新设置矩形大小。
    */
	void draw(Graphics2D g2) {
		//外部传入的绘制对象
		double width=r.getWidth();//获得表盘外界矩形的宽
		double height=r.getHeight();
		double minValue=Math.min(width, height); //长宽最小值
		double x=r.getX()+width/2;
		double y=r.getY()+height/2; //中心点 x、y 坐标
		double radius=minValue/2-GAP; //计算半径
		Ellipse2D.Double ellipse=new Ellipse2D.Double(x-radius,y-radius,radius*2,radius*2);
		g2.setColor(backgroundColor); //设置背景颜色
		g2.fill(ellipse); //填充表盘背景

		g2.setColor(lineColor);
		Stroke stroke=new BasicStroke(LINE_WIDTH); //设置线宽
		g2.setStroke(stroke);
		g2.draw(ellipse); //绘制表盘边框线
		//g2.draw(new Line2D.Double(x-radius,y,x-radius+LINE_LENGTH,y));
		//g2.draw(new Line2D.Double(x+radius,y,x+radius-LINE_LENGTH,y));
		//g2.draw(new Line2D.Double(x,y-radius,x,y-radius+LINE_LENGTH));
		//g2.draw(new Line2D.Double(x,y+radius,x,y+radius-LINE_LENGTH)); //绘制刻度线,还有刻度值、部分刻度线还没有完成,需要继续补充
		
		for(int i=0;i<12;++i){//循环实现刻度线
			double size=4;
			if(i%3==0) size=8;
			drawMark(g2,x,y,radius,size,i);
		}
		//刻度值3,6,9,12的输出
		g2.drawString("12", (int)x - 5, (int)y- (int)radius + 20);
		g2.drawString("9", (int)x - (int)radius + 11, (int)y + 5);
		g2.drawString("3", (int)x + (int)radius - 18, (int)y + 3);
		g2.drawString("6", (int)x - 3, (int)y + (int)radius - 11);
	}
	private void drawMark(Graphics2D g2,double x,double y,double radius,double size,int index) {
		double angle=90;
		angle-=index*30;
		double x1=x+radius*Math.cos(Math.PI*angle/180);
		double y1=y-radius*Math.sin(Math.PI*angle/180);
		radius-=size;
		double x2=x+radius*Math.cos(Math.PI*angle/180);
		double y2=y-radius*Math.sin(Math.PI*angle/180);
		g2.draw(new Line2D.Double(x1, y1, x2, y2));
	}
}

Arm:

import java.awt.geom.*;
import java.time.LocalTime;
import java.awt.*;
public class Arm {
	//指针类,用来显示时、分、秒指针
	public enum Type{HOUR,MINUTE,SECOND}; //枚举类型,指针类型
	private Type type; //指针类型
	private Color armColor=Color.BLUE; //指针颜色
	private Rectangle2D r; //外接矩形大小
	
	public Arm(Type t){
		type=t;
	}
	public void setRectangle(Rectangle2D rect){
		r=rect;
	}
	public void setColor(Color c){
		armColor=c;
	}
	
	public void draw(Graphics2D g2) {
		LocalTime time=LocalTime.now(); //获取系统当前时间
		int h=time.getHour()%12;
		int m=time.getMinute();
		int s=time.getSecond();
		double angle=90,size=0;
		
		double x=r.getX()+r.getWidth()/2;
		double y=r.getY()+r.getHeight()/2; //计算中心点
		size=Math.min(r.getWidth()/2, r.getHeight()/2);
		
		switch(type){ //根据指针类型、时间计算角度和长度
		case HOUR:
		     angle=90-h*30-m/2;
		     size*=18.0/30;
	         break;
		case MINUTE:
		     angle=90-m*6-s/10;
		     size*=20.0/30;
		     break;
		case SECOND:
		     angle=90-s*6;
		     size*=23.0/30;
		     break;
		}
		
		g2.setColor(armColor);
		//double x1=x+size*Math.cos(Math.PI*angle/180);
		//double y1=y-size*Math.sin(Math.PI*angle/180); //计算末端坐标
		//g2.draw(new Line2D.Double(x, y, x1, y1));
		
		//换成三角状的指针
		int[] xpoint=new int[5];
		int[] ypoint=new int[5];
		double angle1=angle-90;
		double size1=size/10;
		double size2=size/5;
		double dy1=size1*Math.sin(Math.PI*angle1/180);
		double dx1=size1*Math.cos(Math.PI*angle1/180);
		xpoint[0]=(int)(x+dx1);
		ypoint[0]=(int)(y-dy1);

		double dy2=size*Math.sin(Math.PI*angle/180);
		double dx2=size*Math.cos(Math.PI*angle/180);
		xpoint[1]=(int)(x+dx2);
		ypoint[1]=(int)(y-dy2);
		
		xpoint[2]=(int)(x-dx1);
		ypoint[2]=(int)(y+dy1);
		
		double dy3=size2*Math.sin(Math.PI*angle/180);
		double dx3=size2*Math.cos(Math.PI*angle/180);
		xpoint[3]=(int)(x-dx3);
		ypoint[3]=(int)(y+dy3);
		
		xpoint[4]=xpoint[0];
		ypoint[4]=ypoint[0];
		
		Polygon poly=new Polygon(xpoint,ypoint,5);
		g2.fillPolygon(poly);
		
		final double radius=5;
		Ellipse2D.Double ellipse=new Ellipse2D.Double(x-radius,y-radius,radius*2,radius*2);
		g2.setColor(Color.BLACK);
		g2.fill(ellipse); //绘制中心圆点
	}
	public void draw1(Graphics2D g2) {
		LocalTime time=LocalTime.now(); //获取系统当前时间
		int h=time.getHour()%12-11;
		int m=time.getMinute();
		int s=time.getSecond();
		double angle=90,size=0;
		
		double x=r.getX()+r.getWidth()/2;
		double y=r.getY()+r.getHeight()/2; //计算中心点
		size=Math.min(r.getWidth()/2, r.getHeight()/2);
		
		switch(type){ //根据指针类型、时间计算角度和长度
		case HOUR:
		     angle=90-h*30-m/2;
		     size*=18.0/30;
	         break;
		case MINUTE:
		     angle=90-m*6-s/10;
		     size*=20.0/30;
		     break;
		case SECOND:
		     angle=90-s*6;
		     size*=23.0/30;
		     break;
		}
		
		g2.setColor(armColor);
		//double x1=x+size*Math.cos(Math.PI*angle/180);
		//double y1=y-size*Math.sin(Math.PI*angle/180); //计算末端坐标
		//g2.draw(new Line2D.Double(x, y, x1, y1));
		
		//换成三角状的指针
		int[] xpoint=new int[5];
		int[] ypoint=new int[5];
		double angle1=angle-90;
		double size1=size/10;
		double size2=size/5;
		double dy1=size1*Math.sin(Math.PI*angle1/180);
		double dx1=size1*Math.cos(Math.PI*angle1/180);
		xpoint[0]=(int)(x+dx1);
		ypoint[0]=(int)(y-dy1);

		double dy2=size*Math.sin(Math.PI*angle/180);
		double dx2=size*Math.cos(Math.PI*angle/180);
		xpoint[1]=(int)(x+dx2);
		ypoint[1]=(int)(y-dy2);
		
		xpoint[2]=(int)(x-dx1);
		ypoint[2]=(int)(y+dy1);
		
		double dy3=size2*Math.sin(Math.PI*angle/180);
		double dx3=size2*Math.cos(Math.PI*angle/180);
		xpoint[3]=(int)(x-dx3);
		ypoint[3]=(int)(y+dy3);
		
		xpoint[4]=xpoint[0];
		ypoint[4]=ypoint[0];
		
		Polygon poly=new Polygon(xpoint,ypoint,5);
		g2.fillPolygon(poly);
		
		final double radius=5;
		Ellipse2D.Double ellipse=new Ellipse2D.Double(x-radius,y-radius,radius*2,radius*2);
		g2.setColor(Color.BLACK);
		g2.fill(ellipse); //绘制中心圆点
	}
}

最后可以在Eclipse中建立一个包文件,将这些类放入其中即可。

程序运行结果如下:

java可视化编程实践--桌面时钟_第1张图片

两个时钟:第一个是中国时间,第二个是美国纽约时间

如果只想在界面中显示一个时钟的话,直接在ClockComponent类中删除一个时钟定义即可。




做这个时钟界面时发现一个实现的比较基础的可视化时钟程序,感觉也挺好的:

https://blog.csdn.net/qq_24653023/article/details/52195190


你可能感兴趣的:(Java)