看得见的算法——验证通过简单的动画验证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.边缘碰撞检测
当我们的圆移动到不能使它完整显示的时候就反向移动
‘