画图板数据的存取

前段时间作了个简单的画图板,能够画直线,矩形,椭圆,三角形四种颜色以及能够选择各种形状的颜色。首先来看一下此画图板的截图,如下图:

[img]http://dl.iteye.com/upload/attachment/527484/aa5000e9-024b-3a0c-97cf-441a818cbf5e.png[/img]


现在主要总结将此画图板上的数据保存为文件,这里的保存只能用自己的画图板打开,不能用其他图片查看器打开。
在Java中DataInputStream和DataOutputStream这两种流主要用来读写指定的数据类型,比如要读取一个8字节的Long型数据,读取一个4字节的int型数据,用这两种流非常方便。有了前面对流的使用经验和总结,就很容易掌握这两种流的使用。但是首先还需要来看在API文档中这两种流的构造方法和其他方法摘要。这两种流都只有一个构造方法,分别是DataInputStream(InputStream in)和DataOutputStream(OutputStream out)。了解了这两个流之后,就可以对画图板数据的保存和读取了。首先先介绍用自定义队列对画图板数据的保存,由前面对流的使用的经验,先来创建一个方法writeFile()对画图板数据的保存,再向该方法中传入要保存的文件路径和形状队列两个参数。再创建文件输出流和数据输出流对象分别为:java.io.FileOutputStream fos = new java.io.FileOutputStream(path); java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);然后再用writeInt(int v)方法写出队列的长度,接着遍历队列,判断队列中每个元素的形状类型,在得到各形状类型的属性,最后分别写出各形状的属性数据。具体代码如下:

/**
* 将图片保存到指定文件
* @param path:文件的指定路径
* @param list:形状队列
*/
public void writeFile(String path,ListTest<Shape> list){

try{
//创建输出流对象
java.io.FileOutputStream fos = new java.io.FileOutputStream(path);
//创建数据输出流对象
java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);

//写出队列的长度
dos.writeInt(list.size());

//遍历队列
for (int i=0;i<list.size();i++){
//取出队列的元素
Shape sh = list.get(i);

byte type = sh.type;
//写出形状的类型
dos.writeByte(type);

if (type==0){//如果是直线
//强制转型
Line line = (Line)sh;
//获得直线的属性
int x1 = line.x1;
int y1 = line.y1;
int x2 = line.x2;
int y2 = line.y2;
int color = line.color.getRGB();

//写出直线的属性
dos.writeInt(x1);
dos.writeInt(y1);
dos.writeInt(x2);
dos.writeInt(y2);
dos.writeInt(color);

}else if (type==1){//如果是矩形
Rect rect = (Rect)sh;
//获得矩形的属性
int x1 = rect.x1;
int y1 = rect.y1;
int x2 = rect.x2;
int y2 = rect.y2;
int color = rect.color.getRGB();

//写出矩形的属性
dos.writeInt(x1);
dos.writeInt(y1);
dos.writeInt(x2);
dos.writeInt(y2);
dos.writeInt(color);


}else if (type==2){//如果是椭圆
Oval oval = (Oval)sh;
//获得椭圆的属性
int x1 = oval.x1;
int y1 = oval.y1;
int x2 = oval.x2;
int y2 = oval.y2;
int color = oval.color.getRGB();

//写出椭圆的属性
dos.writeInt(x1);
dos.writeInt(y1);
dos.writeInt(x2);
dos.writeInt(y2);
dos.writeInt(color);


}else if (type==3){//如果是三角形
Triangle tg = (Triangle)sh;
//获得三角形的属性
int x1 = tg.x1;
int y1 = tg.y1;
int x2 = tg.x2;
int y2 = tg.y2;
int color = tg.color.getRGB();

//写出三角形的属性
dos.writeInt(x1);
dos.writeInt(y1);
dos.writeInt(x2);
dos.writeInt(y2);
dos.writeInt(color);


}

}

//强制输出
dos.flush();
//关闭输出流
fos.close();

}catch(Exception et){
et.printStackTrace();
}

}

将保存的数据读取是上面保存数据的一个逆过程,首先先定义一个方法readFile(),传入要读取文件的路径参数,该方法的返回值是一个自定义队列。首先要实例化一个自定义队列:ListTest<Shape> list = new ListTest<Shape>();然后和上面一样创建文件输入流和数据输入流对象,分别为:java.io.FileInputStream fis = new java.io.FileInputStream(path);和java.io.DataInputStream dis = new java.io.DataInputStream(fis);再根据上面写出的顺序,上面是怎么写出的,这里就要怎么读取,最后要创建各种形状的对象加入到自定义队列中。具体代码如下所示:
/**
* 将制定 的文件读取到内存中
* @param path:指定文件路径
* @return:返回形状队列
*/
public ListTest<Shape> readFile(String path){
//实例化一个队列
ListTest<Shape> list = new ListTest<Shape>();

try{
//创建输入流对象
java.io.FileInputStream fis = new java.io.FileInputStream(path);
//创建数据输入流对象
java.io.DataInputStream dis = new java.io.DataInputStream(fis);

//读入一个Int,作为队列的长度
int len = dis.readInt();

//遍历数组
for (int i=0;i<len;i++){
//读入一个byte
byte type = dis.readByte();

if (type==0){//如果是直线
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
Color color =new Color(dis.readInt());

//创建直线对象
Line line = new Line(x1,y1,x2,y2,color);
//将直线加入到队列中
list.add(line);

}else if (type==1){//如果是矩形
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
Color color =new Color(dis.readInt());

//创建直线对象
Rect rect = new Rect(x1,y1,x2,y2,color);
//将直线加入到队列中
list.add(rect);

}else if (type==2){//如果是椭圆
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
Color color =new Color(dis.readInt());

//创建直线对象
Oval oval = new Oval(x1,y1,x2,y2,color);
//将直线加入到队列中
list.add(oval);

}else if (type==3){
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
Color color =new Color(dis.readInt());

//创建直线对象
Triangle tg = new Triangle(x1,y1,x2,y2,color);
//将直线加入到队列中
list.add(tg);
}

}

//关闭输入流
fis.close();

}catch(Exception et){
et.printStackTrace();
}


return list;
}

接下来要总结一种山寨BMP保存画图板的数据。这种保存方式的原理是将画图的区域看成是一个一个的像素点,根据画得图形的颜色与背景颜色的值不同分别画出各点形成画得形状图形。首先要定义一个类,该类的作用就是要获取所保存区域的存有各点颜色值的二维颜色数组。思路是获取要保存的区域,这里是Jpanel区域,然后得到Jpanel左上角相对于屏幕的坐标,根据左上角的坐标创建一个屏幕区域对象,再创建一个Robot类的对象,从屏幕截取图像既可以得到图像上每个坐标点的颜色值,最后创建一个二维数组将颜色值对应的保存到数组中。具体代码如下所示:
/**
* 山寨BMP保存
*
* @author Administrator
*
*/
public class Save4Bit {

static int width;
static int height;
static int[][] colors;// 用来保存每一个像素点颜色的数组
static java.awt.Robot robot;

public static void savePic(JPanel panel) {

try {
robot = new java.awt.Robot();
} catch (Exception ef) {
ef.printStackTrace();
}
//得到JPanel的宽度与长度
width = panel.getWidth();
height = panel.getHeight();
colors = new int[height][width];

// 得到panel左上角的点相对于屏幕的坐标
Point p = panel.getLocationOnScreen();

java.awt.Rectangle rect = new java.awt.Rectangle(p.x, p.y,
panel.getWidth(), panel.getHeight());
// 从屏幕上抓取一张图片
java.awt.image.BufferedImage img = robot.createScreenCapture(rect);

for (int i = 0; i < colors.length; i++) {
for (int j = 0; j < colors[i].length; j++) {
colors[i][j] = img.getRGB(i, j);
}
}

}
}
这样作之后,画图板的重绘就与上面那种方式不同了,具体的请比较两种重绘的代码:
第一种保存方式的重绘代码:
//当窗体改变时,该方法自动调用
public class MyPanel extends JPanel{
public void paint(java.awt.Graphics g){
//调用父类的方法
super.paint(g);

//遍历队列的元素
for (int i=0;i<lines.size();i++){
Shape sh = lines.get(i);
sh.draw(g);
}
}

}
第二种保存重绘的代码:
//当窗体改变时,该方法自动调用
public class DrawPanel extends JPanel{
public void paint(java.awt.Graphics g){
//调用父类的方法
super.paint(g);
if (Save4Bit.colors!=null){
//遍历colors数组,取出它的元素,即点的颜色再重新画
for (int i=0;i<Save4Bit.colors.length;i++){
for (int j=0;j<Save4Bit.colors[i].length;j++){

int rgb = Save4Bit.colors[i][j];
if (panel.getBackground().getRGB()!=rgb){
Color color=new Color(rgb);
g.setColor(color);
g.drawLine(i, j, i, j);

}

}
}
}

}

}

获取颜色数组之后就要对数组元素数据的读取和保存了,方法与上面差不多,具体如下:
import javax.swing.JPanel;
/**
* 山寨BMP保存画板
* @author lenovo
*
*/
public class SaveFile {
JPanel panel = new JPanel();

//构造方法
public SaveFile(JPanel panel){
this.panel = panel;
}
/**
* 将数据保存到指定文件
* 1.创建输出流和数据输出流
* 2.首先要得到颜色数组
* 3.写出数组的两个长度
* 4.最后写出数组的每个元素的数据
* @param path:指定文件的路径
* @param colors:像素点颜色的数组
*/
public void writeFile(String path,int[][] colors){
Save4Bit.savePic(panel);
try{
//创建输出流对象
java.io.FileOutputStream fos = new java.io.FileOutputStream(path);

java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(fos);
//创建数据输出流对象
java.io.DataOutputStream dos = new java.io.DataOutputStream(bos);

//写出数组的两个长度
dos.writeInt(Save4Bit.height);
dos.writeInt(Save4Bit.width);

//遍历数组写出数组各元素的数据
for (int i=0;i<colors.length;i++){
for (int j=0;j<colors[i].length;j++){
dos.writeInt(colors[i][j]);
}
}

dos.flush();
fos.close();
}catch(Exception et){
et.printStackTrace();
}

}
/**
* 将指定文件读到内存中
* 1.创建一个二维数组
* 2.创建输入流和数据输入流
* 3.先读取两个Int作为二维数组的长度
* 4.再读取数据存到数组中
* @param path:指定文件的路径
* @return:返回颜色数组
*/
public int[][] readFile(String path){

try{
//创建输入流对象
java.io.FileInputStream fis = new java.io.FileInputStream(path);

java.io.BufferedInputStream bis = new java.io.BufferedInputStream(fis);

//创建数据输入流对象
java.io.DataInputStream dis = new java.io.DataInputStream(bis);

//读取数组的两个长度
int height = dis.readInt();
int width = dis.readInt();

//创建一个二维数组
int[][] colors = new int[height][width];

for (int i=0;i<height;i++){
for (int j=0;j<width;j++){
colors[i][j]=dis.readInt();
}
}

fis.close();
return colors;

}catch(Exception et){
et.printStackTrace();
}

return null;

}

}
这样在保存和打开两个按钮上加上监听器,然后在分别创建对象调用相应的方法就可以对画图板数据的保存和读取了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值