看得见的算法——验证通过简单的动画验证GUI框架

看得见的算法——验证通过简单的动画验证GUI框架

本次我们验证我们的GUI框架

首先我们这里引入java事件机制

1.keyAdapter
2.mouseAdapter

在这里插入图片描述

视图层

package com.lipengge.algorithmic.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.lipengge.algorithmic.model.Circle;
import com.lipengge.randomquestion.util.AlgoVisHelper;

public class AlgoFrame extends JFrame{
	/**
	 * 
	 */
	private static final long serialVersionUID = -3035088527551930125L;
	private int canvasWidth;//画布的宽
	private int canvasHeight;//画布的长
	private Circle[] circles;
   public int getCanvasWidth() {
		return canvasWidth;
	}
	public int getCanvasHeight() {
		return canvasHeight;
	}
	public void render(Circle[] circles){
		this.circles=circles;
		repaint();
	}
   public AlgoFrame(String title,int  canvasWidth, int canvasHeight){
	  super(title);
	  this.canvasWidth=canvasWidth;
	  this.canvasHeight=canvasHeight;
	  setDefaultCloseOperation(EXIT_ON_CLOSE);
	  setResizable(false);//关闭可拖动
	  setVisible(true);
	  AlgoCanvas algoCanvas = new AlgoCanvas();
	  setContentPane(algoCanvas);
	  pack();
   }
   //设置面板JPanel
   class AlgoCanvas extends JPanel{
	/**
	 * 
	 */
	private static final long serialVersionUID = -6056196800598676936L;
    private  AlgoCanvas(){
    	//开启双缓存
    	super(true);
    }
	@Override
	//在面板上绘制内容
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d=(Graphics2D) g;
		AlgoVisHelper.setRenderingHints(g2d);//设置抗锯齿
		AlgoVisHelper.setStrokeWidth(g2d, 1);//设置边的宽度为5
		AlgoVisHelper.setColor(g2d, Color.green);//设置画笔颜色
		for(Circle circle:circles){
			//如果填充属性为假则描边否则填充
			if(!circle.isFilled){
				AlgoVisHelper.strokeCircle(g2d,circle.x,circle.y,circle.getR());
			}else{
				AlgoVisHelper.fillCircle(g2d,circle.x,circle.y,circle.getR());
			}
		}
	}
	@Override
	public Dimension getPreferredSize() {
		return new Dimension(canvasWidth,canvasHeight);
	}
   }
}

控制层

package com.lipengge.algorithmic.controller;

import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import com.lipengge.algorithmic.model.Circle;
import com.lipengge.algorithmic.view.AlgoFrame;
import com.lipengge.randomquestion.util.AlgoVisHelper;

public class AlgoVisualizer {
	private AlgoFrame frame;
	private Circle[] circles;
	private boolean isAnim=true;
	public AlgoVisualizer(int screenWidth,int screenHeight,int Number,int R){
		//圆数组存储要绘制圆的个数
		circles=new Circle[Number];
		//初始化圆的数据
		for(int i=0;i<Number;i++){
			int x=(int)(Math.random()*(screenWidth-2*R))+R;//x坐标
			int y=(int)(Math.random()*(screenHeight-2*R))+R;//y坐标
			int vx=(int)(Math.random()*11)-5;//随机x方向速度
			int vy=(int)(Math.random()*11)-5;//随机y方向速度
			circles[i]=new Circle(x,y,R,vx,vy);//构造对象
		}
		//初始化视图
		EventQueue.invokeLater(()->{
			frame=new AlgoFrame("GUI验证",screenWidth,screenHeight);
			frame.addKeyListener(new AlgoKeyListener());//添加键盘时间
			frame.addMouseListener(new AlgoMouseListener());//添加鼠标事件
			new Thread(()->run(screenWidth,0,screenHeight,0)).start();
		});
	}
	//播放动画
	public void run(int maxx,int minx,int maxy,int miny){
		while(true){
			frame.render(circles);
			AlgoVisHelper.pause(40);
			//如果没有暂停播放动画
			if(isAnim){
			for(Circle circle:circles){
				circle.move(maxx, minx, maxy, miny);
			}
			}
		}
	}
	private class AlgoKeyListener extends KeyAdapter{
		public void keyReleased(KeyEvent event) {
			//如果释放空格键如果播放就暂停如果暂停就播放
			if(event.getKeyChar()==' '){
				isAnim=!isAnim;
			}
		}
	}
	private class AlgoMouseListener extends MouseAdapter{
		//如果释放鼠标左键没填充就填充,填充则改为非填充
		  public void mouseReleased(MouseEvent event) {
			  //因为我们添加的是窗体的鼠标事件它的坐标包括上部的菜单栏这个方法就是偏移坐标的方法
			  //frame.getBounds().height窗体的高度
			  //frame.getCanvasHeight()Jpanel的高度
			  //-(frame.getBounds().height-frame.getCanvasHeight())向下偏移一个菜单栏的高度差
			  event.translatePoint(0, -(frame.getBounds().height-frame.getCanvasHeight()));
			  //对符合坐标的圆进行颜色改变
			  for(Circle circle:circles){
				  if(circle.contains(event.getPoint())){
					  circle.isFilled=!circle.isFilled;
				  }
			  }
		  }
	}
 public static void main(String[] args) {
  new AlgoVisualizer(1000,1000,10,50);
  }
}

模型层‘

package com.lipengge.algorithmic.model;

import java.awt.Point;

public class Circle {
	public int x;//圆心坐标x
	public int y;//圆心坐标y
	private int r;//圆半径
	public int vx;//x轴方向速度
	public int vy;//y轴方向速度
	public boolean isFilled=false;//是否填充
	public Circle(int x, int y, int r, int vx, int vy) {
		this.x = x;
		this.y = y;
		this.r = r;
		this.vx = vx;
		this.vy = vy;
	}
	//获取圆的半径
	public int getR() {
		return r;
	}
	public void move(int maxx,int minx,int maxy,int miny){
		x+=vx;
		y+=vy;
		checkCollision(maxx,minx,maxy,miny);
	}
	//碰撞检测
	private void checkCollision(int maxx,int minx,int maxy,int miny){
		if(x-r<minx){
			x=r;
			vx=-vx;
		}
		if(x+r>=maxx){
			x=maxx-r;
			vx=-vx;
		}
		if(y-r<miny){
			y=r;
			vy=-vy;
		}
		if(y+r>=maxy){
			y=maxy-r;
			vy=-vy;
		}
	}
	//判断鼠标点击到圆心的距离
	public boolean contains(Point p){
		return Math.pow(x-p.x, 2)+Math.pow(y-p.y, 2)<=Math.pow(r, 2);
	}

}

辅助类

package com.lipengge.algorithmic.util;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

public class AlgoVisHelper {
	private AlgoVisHelper(){}
	//画圆描边的辅助类
	public static void strokeCircle(Graphics2D g,int x,int y,int r){
		//圆数据的闭包
		Ellipse2D circle = new Ellipse2D.Double(x-r,y-r,2*r,2*r);
		g.draw(circle);
	}
	//画圆填充的辅助类
	public static void fillCircle(Graphics2D g,int x,int y,int r){
		Ellipse2D circle = new Ellipse2D.Double(x-r,y-r,2*r,2*r);
		g.fill(circle);
	}
	//画矩形的辅助类
	public static void strokeReactangle(Graphics2D g,int x,int y,int width,int height){
		Rectangle2D reactangle = new Rectangle2D.Double(x,y,width,height);
		g.draw(reactangle);
	}
	//填充矩形的辅助类
	public static void fillReactangle(Graphics2D g,int x,int y,int width,int height){
		Rectangle2D reactangle = new Rectangle2D.Double(x,y,width,height);
		g.fill(reactangle);
	}
	//设置画笔颜色
    public static void setColor(Graphics2D g,Color color){
    	g.setColor(color);
    }
    //设置边的宽度和平滑性
    public static void setStrokeWidth(Graphics2D g,int w){
    	//BasicStroke.CAP_ROUND把定点变为圆弧半径为画笔一半
    	//BasicStroke.JOIN_ROUND把线条连接点变为弧形
    	g.setStroke(new BasicStroke(w,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
    }
    //设置抗锯齿
    public static void setRenderingHints(Graphics2D g){
    	RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    	hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    	g.addRenderingHints(hints);
    }
    public static void pause(long millsecond){
    	try {
			Thread.sleep(20);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
    }
    
}

这里我们来说一下重点圆初始化的注意事项

1.圆的位置问题

在这里插入图片描述

2.边缘碰撞检测

当我们的圆移动到不能使它完整显示的时候就反向移动

在这里插入图片描述

上述代码就是当x减去一个半径小于零的时候让x等于半径反向移动y同理
当x加上一个半径大于高的时候然x等于高度减r反向移动y同理
演示效果图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值