在我的上一篇博客(http://1316478764.iteye.com/admin/b
logs/1948471),我简单实现了一个
画图板,但是仍有很大的bug,当窗体大小发生改变时,我们会
发现之前画的图形会遭到破坏,甚至最小化后再打开,图形完全消失。导致这个bug的原因也很简单,因为
内存中没有保存这些图形,接下来我们就具体探讨一下这个问题。
首先我们要知道当窗体大小发生改变时,系统会自动调用JFrame的paint方法,因为我们画的图形是存在
缓存中,当窗体大小改变后,这些缓存会自动清空,paint方法不会
重绘这些图形,只会重绘窗体上的组件。知道所以然后就好办了,我们要做的就是将这些图形保存到内存中,当窗体进行重绘时,再将这些图形从内存中取出,画出来,即重写paint方法。
至于怎么保存图形,学过
队列的童鞋肯定无压力,我们可以创建一个保存图形类对象的队列,当我们在画图板上每画一个图形,就保存一个,然后重写paint方法时,我们只需要遍历这个队列,将保存的图形在画出来就ok了。看点代码吧:
class="java" name="code">public class MyList<E> {
private Object src[] = new Object[0];
public void add(E e) {
Object dest[] = new Object[src.length + 1];
dest[src.length] = e;
System.arraycopy(src, 0, dest, 0, src.length);
src = dest;
}
public E get(int index) {
Object e = src[index];
return (E) e;
}
队列中需要哪些方法,是根据我们想实现的功能来决定的,我们想实现重绘的话,上面两个方法应该够用了。
至于图形类,我们创建一个Shape类,里面包含了图形的每个属性,还有画图形的方法,代码如下:
public class Shape {
int x1,y1,x2,y2;//画图形需要的起点和终点坐标
Color color;//线的颜色
Stroke st;//画笔的粗细
Byte type;//金字塔:0 立方体:1 鸡蛋:2
Boolean flag=true;//用作标记shape对象是否显示(用于撤销和重做)true:显示 false:不显示
public void drawShape(Graphics g){此处省略若干行代码}
保存图形类的队列我们已经实现,接下来我们只要给Shape类的各个属性赋值,画出图形并保存图形
//绘制图形
shape.drawShape(g);
//将图形保存到队列中
shapeList.add(shape);
到这儿就基本完成工作了,最后我们只需重写画布的paint方法
public void paint(Graphics g){
super.paint(g);
//note:一定要取对画布!!!获取jp_addto的画布,所以在jp_addtojp里重写paint方法更好,还能避免上方jpanel的闪烁
//遍历队列,重新绘制出保存到图形
for(int i=0;i<shapeList.size();i++){
Shape shape=shapeList.get(i);
shape.drawShape(g);
}
}
ok,我们在运行看看,会发现最小化后再打开,还是能看到之前的图形,嘎嘎,是不是感觉自己又进步了一点。但是难道重绘只能这样应用么,我们还能不能用重绘来完成其他的功能呢??
当然可以,还记得你画错图形但却不能删除的苦恼么么,我们通过重绘就可以实现撤销和重做操作,还可以实现清空画布。撤销不就是把刚刚保存的Shape对象不画出来,然后再重绘,而重做不就是将之前不让画出来的图形再画出来么。这两个功能我们通过对每个Shape对象设置一个标志决定是否画出来来实现,即上面Shape类代码中定义的flag属性。至于清空画布就更简单,我们将队列中的所有Shape类对象全删了不就完事。当然,这需要我们在队列中添加delete方法。