一、为什么要重绘
1、计算机有三种存储数据的存储器--外存、内存和缓存。缓存就是计算机里的硬盘,外存的特点 是可以永久地保存数据(在硬盘不会损坏的情况下),它的缺点是:存储数据和读取数据的速度 很慢。内存是介于外存与缓存之间,计算机所要运行的所有程序,必须先从外存读取到内存中, 这当然也包括操作系统。还有内存在通电状态下才有保存数据的作用,如果计算机的电源关闭了 ,内存里的数据也会消失,所以我们在做一些重要的文档时要及时保存数据,这里的保存是将内 存里的数据保存到外存里,也就是硬盘上。缓存是CPU上的一块存储器,它是用来临时保存CPU马 上要处理的数据,一旦里面的数据不需要了,缓存就会马上被清空。
2、我们在画图板上画的图形,它的数据是被临时保存在缓存里的,当我们把窗口最大化或最小化, 或其他的操作是,缓存里的数据就会被清空。而当我们再把窗口还原是,窗口的数据会重新从内存读 到缓存里,经过处理后吧窗体显示,但是因为我们没有把我们画的图形的数据保存起来,所以当窗体 重新显示时,我们之前画的图形并没有显示。所以要让我们画的图形能够重新显示,我们必须把图形 的数据保存起来。
二、重绘的方法
1、用队列来保存数据 队列是用来保存数据的一种数据结构,它相当于一个动态数组,所以我们可以用它来保存我们 在画图板上所画的图形的数据。思路就是我们每画一个图形,就把它保存到队列里去,当需要重 绘时,只需要把队列里的数据重新取出来,把它画到画图板上。
下面是我自定义的保存图形数据 的队列:
public class mylist<E> {
//将数组定义为Object数组,表示能存放Java中所有的对象
private Object[] src = new Object[0];
/**
* 将指定的数据放入队列容器中
*
* @param e
* 要放入队列容器的数据
*/
public void add(E e) {
//定义一个新数组,长度是原始数组长度+1
Object dest[] = new Object[src.length+1];
//将新元素放入新数组最后一个下标位置
dest[src.length] = e;
//将原始数组中的元素按照下标顺序拷贝到新数组
for(int i=0;i<src.length;i++){
dest[i] = src[i];
}
//将原数组名指向新数组
src = dest;
}
/**
* 取出指定下标位置的元素
*
* @param index
* 要取出的元素的下标
* @return 返回取得的元素
*/
public E get(int index) {
//得到src对应下标的元素
E e = (E)src[index];
return e;
}
/**
* 删除指定位置的元素
*
* @param index
* 要删除的元素的下标
*/
public void delete(int index) {
//创建一个长度比src小1的数组
Object [] arr =new Object[src.length-1];
//拷贝下表之前的元素
for(int i=0;i<index;i++){
arr[i]=src[i];
}
//拷贝下标之后的元素
for(int j=index;j<src.length;j++){
arr[j]=src[j+1];
}
//修改后让src指向arr
src=arr;
}
/**
* 将指定位置的元素修改为指定的值
*
* @param index
* 要修改的元素的下标
* @param num
* 修改之后的新值
*/
public void modify(int index, E e) {
src[index] = e;
}
/**
* 在指定的位置插入指定的元素值
*
* @param index
* 要插入元素的位置
* @param e
* 要插入的元素
*/
public void insert(int index, E e) {
//创建一个比src大1的数组
Object [] arr =new Object[src.length+1];
//拷贝添加的元素下标之前的元素
for(int i=0;i<index;i++){
arr[i]=src[i];
}
//添加要插入的元素
arr[index]=e;
//拷贝添加元素下标之后的元素
for(int j=index;j<arr.length;j++){
arr[j+1]=src[j];
}
//让src重新指向arr
src=arr;
}
/**
* 得到容器中元素个数的方法
*
* @return 返回容器中的元素个数
*/
public int size() {
//队列长度就是src数组的当前长度
int len = src.length;
return len;
}
}
还有一个用来保存图形相关信息的一个类:
public class myshape {
//定义形状的属性
private byte type;
//保存坐标的属性
private int x1,y1,x2,y2;
//设置颜色属性
private Color color;
//设置形状的方法
public void setShape(byte type){
this.type=type;
}
//获取形状的方法
public byte getShape(){
return type;
}
//给坐标赋值的 方法
public void setvalue(int x1,int y1,int x2,int y2){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
}
//获取x1坐标值的方法
public int getx1(){
return x1;
}
//获取y1坐标值的方法
public int gety1(){
return y1;
}
//获取x2坐标值的方法
public int getx2(){
return x2;
}
//获取y2坐标值的方法
public int gety2(){
return y2;
}
//定义设置颜色的方法
public void setcolor(Color color){
this.color=color;
}
//定义获得颜色的方法
public Color getcolor() {
return color;
}
}
重绘部分的代码
//在调用子类重写了的方法时,需要先调用父类中原有的方法???
public void paint(Graphics g) {
super.paint(g);//调用父类中的方法
//把原来画的东西,自己写代码,再画出来!
//获得队列对象
mylist mlis=drl.getMylist();
for(int i=0;i<mlis.size();i++){
//获得队列中的元素
Object ms=mlis.get(i);
//强制转换为myshape类型
myshape sp=(myshape)ms;
//画直线
if(sp.getShape()==1){
//设置颜色
hb.setColor(sp.getcolor());
hb.drawLine(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2());
}
//画圆
if(sp.getShape()==2){
//设置颜色
hb.setColor(sp.getcolor());
hb.drawOval(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2());
}
//画矩形
if(sp.getShape()==3){
//设置颜色
hb.setColor(sp.getcolor());
hb.drawRect(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2());
}
// 话填充矩形
if(sp.getShape()==4){
//设置颜色
hb.setColor(sp.getcolor());
hb.fillRect(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2());
}
//画填充圆
if(sp.getShape()==5){
//设置颜色
hb.setColor(sp.getcolor());
hb.fillOval(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2());
}
}
}
用这种方法进行重绘,十分严重的问题是当画的形状过多时,队列里面会保存大量的数据,而很多又是不需要的,所以我们得用另一种方法来重绘
2、用数组来保存数据 数组怎么用来保存图形的信息呢?
首先,让我们先了解一下计算机屏幕显示图像的原理。我们在 屏幕上看到的图像其实是有一个个像素点组成的,每个像素点可以显示不同的颜色,于是不同颜色 的像素点有机的组合在一起,便形成了丰富多彩的图像。根据这一点,想想如果我们能把屏幕上的 每个像素点的颜色信息保存起来,不就能把画图板上的图像信息保存了吗。而像素点的颜色值可以 用一个整数来表示,又画图板是一个矩形区域,所以用一个二维数组来保存是最合适的。
下面是保存画图板上每个像素点的颜色值的主要代码:
// 获取drawPanel左上角的相对于屏幕的位置
Point point = drjp.getLocationOnScreen();
// 获取drawPanel的大小
java.awt.Dimension dim = drjp.getPreferredSize();
// 创建一个要截取的区域对象(就是drawPanel所占据的区域)
java.awt.Rectangle rect = new java.awt.Rectangle(point, dim);
// 绘制完一个图像就截屏
BufferedImage img = robot.createScreenCapture(rect);
// 根据图像创建二维数组
data = new int[img.getHeight()][img.getWidth()];
// 将图像上的每一个点的颜色存储到数组中
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
int rgb = img.getRGB(j, i);
// 将坐标和下标对应保存颜色
data[i][j] = rgb;
}
}