好久没有总结了,总结确实应该是经常性的,不然先前觉得很惊天动地的收获时间久了甚至都会忘记,这次的优化主要在于这几个方面,首先是功能的完善,到写博客为止,已经实现的功能有直线,矩形,椭圆,刷子,橡皮,铅笔以及各种颜色的选择和以上图形的重绘功能,将要实现的功能是喷漆,多边形,圆角矩形,曲线等,其中圆角矩形比较简单,当然,也包括以上形状的重绘,还有一些细节的优化,好吧,就先展望到现在,现在来总结一下这阶段的收获,首先这个阶段其实最重要的是重绘功能的实现,右最开始的保存坐标和标志来重绘,到后来的通过保存图形对象来实现,第一次这么深刻地体会到面向对象的思想具体实现。至于其他各种功能的实现,其实最重要的是思维逻辑问题来实现那些功能,这些其实不用斌哥一个一个地讲,最重要的是自己要好好想清楚怎么实现。
首先回顾一下第一阶段重绘的实现,在这个阶段,重绘是通过定义一个自定义队列,用来保存和取其中的元素,考虑到数组只能设置固定大小,所以设置自定义队列用来实现能够动态改变数组的大小,其具体的实现是这样的:
public class MyList{
Shape[] srcArry=new Shape[0];
public void add( Shape e){
Shape[] destArry=new Shape[srcArry.length+1];
for(int i=0;i<srcArry.length;i++){
destArry[i]=srcArry[i];
}
destArry[srcArry.length]=e;
srcArry=destArry;
}
public Shape get(int i){
return srcArry[i];
}
public int getLength(){
return srcArry.length;
}
}
然后实现重绘的功能是通过在每次画图之后保存坐标和标志,因为坐标和标志是不同类型,所以在设置自定义队列的时候要把类型定义为Object类,这样可以保存不同类型的元素,等到用的时候再通过强制转型把他转换成相应的类型就行,这样元素的保存与取用实现了,关键在于怎样保存坐标和怎样在重绘方法里面取用坐标,首先保存坐标,在每次画图之后保存画图的四个坐标,即两个点,然后还有command标志和color,保存的操作是这样的:
public void mouseReleased(MouseEvent e) {
if("line".equals(command)||"rect".equals(command)||"oval".equals(command)){
x2 = e.getX();
y2 = e.getY();
BasicStroke basicstroke=new BasicStroke(1);
Graphics2D gr=(Graphics2D) g;
gr.setStroke(basicstroke);
mylist.add(x1);
mylist.add(y1);
mylist.add(x2);
mylist.add(y2);
if("line".equals(command)){
g.drawLine(x1,y1,x2,y2);
}else if("rect".equals(command)){
g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x2-x1),Math.abs(y2-y1));
}else if("oval".equals(command)){
g.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x2-x1),Math.abs(y2-y1));
}
mylist.add(color);
}
}
// public void paint(Graphics g){
//
// super.paint(g);
// for(int i=0;i<mylist.getLength()/6;i++){
// int x1 = (Integer)mylist.get(6*i);
// int y1 = (Integer)mylist.get(6*i+1);
// int x2 = (Integer)mylist.get(6*i+2);
// int y2 = (Integer)mylist.get(6*i+3);
// String command = (String)mylist.get(6*i+4);
// Color color = (Color)mylist.get(6*i+5);
// g.setColor(color);
// if("line".equals(command)){
// g.drawLine(x1,y1,x2,y2);
// }else if("rect".equals(command)){
// g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x2-x1),Math.abs(y2-y1));
// }else if("oval".equals(command)){
// g.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x2-x1),Math.abs(y2-y1));
// }else if("pencil".equals(command)){
// g.drawLine(x1,y1,x2,y2);
// }
// }
// }
这样之后就能实现重绘的功能了,但是这样尽管尽管能够实现但是会存在问题,首先就是代码的冗长和杂乱,坐标随处可见,而且万一以后的图形不是用两个坐标实现的话那么又会出现问题,所以想到了要用面向对象里的思想,就是把自定义队列里面的每一个元素保存为每一个图形对象,这样子的话实现操作便会很简洁了,画一个图形的话就保存一个图形,然后重绘的时候就依次取出来每个图形对象就行,思路很清晰,但是要实现的话要做一些准备工作,既然要把自定义队列里面的元素设置为图形类型,那我们肯定要定义一个图形类型,shape类,考虑到有好几中图形,那我们不妨定义一个根类型,然后让其他图形类型比如直线,矩形,椭圆来继承他就行,这里又用到了抽象类的知识,我们把那个根类型shape定义为abstract类型,具体定义是这样的:
public abstract class Shape{
public int x1,y1,x2,y2;
public Graphics g;
public Color color;
public int width;
public Shape(int x1,int y1,int x2,int y2,Color color,int width){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
this.color=color;
this.width=width;
}
public abstract void draw(Graphics g);
}
这样就把根类型定义好了,之后就是实现几种子图形的类了,比如直线,现在以直线为例,他的实现是这样的:
public class Line extends Shape{
public Line(int x1,int y1,int x2,int y2,Color color,int width){
super (x1,y1,x2,y2,color, width);
}
public void draw(Graphics g){
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
}
之后的操作就很简单了,每次画图之后保存一个这样的对象到自定义队列里面,然后重绘的时候再依次取出来,具体的实现是这样子的:
public void mouseReleased(MouseEvent e) {
if("line".equals(command)||"rect".equals(command)||"oval".equals(command)){
x2 = e.getX();
y2 = e.getY();
if("line".equals(command)){
shape=new Line(x1,y1,x2,y2,color, 1);
BasicStroke basicstroke=new BasicStroke(shape.width);
Graphics2D gr=(Graphics2D)g;
gr.setStroke(basicstroke);
shape.draw(gr);
}else if("rect".equals(command)){
shape=new Rect(x1,y1,x2,y2,color,1);
BasicStroke basicstroke=new BasicStroke(shape.width);
Graphics2D gr=(Graphics2D)g;
gr.setStroke(basicstroke);
shape.draw(gr);
}else if("oval".equals(command)){
shape=new Oval(x1,y1,x2,y2,color, 1);
BasicStroke basicstroke=new BasicStroke(shape.width);
Graphics2D gr=(Graphics2D)g;
gr.setStroke(basicstroke);
shape.draw(gr);
}
mylist.add(shape);
}
}
这样子就把每次的图形对象保存到自定义队列里面了,取出来进行重绘的时候是这样子的:
public void paint(Graphics g){
super.paint(g);
for(int i=0;i<mylist.getLength();i++){
if(mylist.get(i).width==1){
BasicStroke basicstroke1=new BasicStroke(mylist.get(i).width);
Graphics2D gr=(Graphics2D) g;
gr.setStroke(basicstroke1);
mylist.get(i).draw(gr);
}
if(mylist.get(i).width==5){
BasicStroke basicstroke2=new BasicStroke(mylist.get(i).width);
Graphics2D gr=(Graphics2D) g;
gr.setStroke(basicstroke2);
mylist.get(i).draw(gr);
}
}
}
这样子就实现了重绘的功能,相对于上一种方法,这种方法的条理更加清晰,其实学习的过程就是这样一步一步地完善的,现在再来说明一下喷漆的实现,这里要用到随机数的方法,每次在mousedragged方法里面会获取一个坐标x2,y2,我们可以以这个点为基准点,然后产生一个随机点,这个随机点的横坐标是-a+x2到+a+x2,纵坐标是-a+y2到+a+y2,就是以基准点为中心的一个正方形里面随机取点,这样就能得到喷漆的功能,其他重绘的方法都类似,这里不再赘述,下面是随机点的获取方法:
else if("airbrush".equals(command)){
int x2 = e.getX();
int y2 = e.getY();
Random random = new Random();
for(int k=0;k<50;k++){
int i = random.nextInt(20);
int j = random.nextInt(20);
int x = x2+(10-i);
int y = y2+(10-j);
shape=new Line(x,y,x,y,color,1);
shape.draw(g);
mylist.add(shape);
}
接下来还要继续优化一些细节问题,会对比着系统的画图板来完善,继续加油!!!