上一篇博文已经具体的构建了画图板的整个框架 这里就具体的说明一下功能的实现问题
一、功能实现
1.简单的画图形
2.重绘:窗体最小化之后 打开窗体 画面不消失
3.保存文件: 把绘制出来的图片放在硬盘里
二、难点分析
三、错误点集合
1.简单的画图形
画图形分为三步:
第一步:取画布
// 给他drawpanel获取画布
java.awt.Graphics g = drawpanel.getGraphics();
第二步:取颜色 取图形
g.setColor(Color.LIGHT_GRAY);
第三步:绘制图形
g.drawLine(x1, y1, x2, y2);
2.重绘:窗体最小化之后 打开窗体 画面不消失
介绍两种方法:
第一种:每个画出的图形用队列保存 重绘时只需遍历队列重画一下
建立队列 每次取到的sh都加到队列里
// 定义一个队列用来存放形状对象~
MyQueue<Shape> shapes;
//建立一个Shape类型的对象把他设置为null
Shape sh = null;
//将图形加入队列
shapes.add(sh);
//把图形画出来
sh.draw(g);
新建一个MyPanel类因为画布是在drawpanel上面取的
遍历形状队列 绘制出图形
class MyPanel extends JPanel {
/**
* 重写JPanel中用来绘制窗体的方法
*/
public void paint(Graphics g) {
// 调用父类的方法来正确的绘制窗体
super.paint(g);
System.out.println("绘制了");
// 遍历形状队列
for (int i = 0; i < shapes.size(); i++) {
// 取出形状
Shape sh = shapes.get(i);
// 绘制
sh.draw(g);
}
}
}
第二种方法:捕捉屏幕方法
因为drawpanel是由屏幕上的像素点组成的
有不同的颜色是因为像素点各点存的颜色不一样,屏幕可以抽象看做一个二维数组
所以只需要取到二维数组里每点的颜色即可
核心是
// 创建Rectangle对象
Rectangle rec = new Rectangle(point, drawDim);
// 捕捉drawpanel上的像素图像
BufferedImage bimg = rb.createScreenCapture(rec);
// 建立一个robot对象
try {
Robot rb = new Robot();
// 获取drawpanel左上角的点~
Point point = drawpanel.getLocationOnScreen();
// 获取drawpanel的dimension
int width = drawpanel.getWidth();
int height = drawpanel.getHeight();
java.awt.Dimension drawDim = new java.awt.Dimension(width, height);
// 创建Rectangle对象
Rectangle rec = new Rectangle(point, drawDim);
// 捕捉drawpanel上的像素图像
BufferedImage bimg = rb.createScreenCapture(rec);
// 现在要找图像上的像素点用一个二维数组来储存每个点的像素
// 为存放屏幕上各点的颜色设置一个二维数组array
Array.pointArray = new int[height][width];
for (int i = 0; i < Array.pointArray.length; i++)
for (int j = 0; j < Array.pointArray[i].length; j++) {
// x是像素的x坐标 j是列 x = 1 为第一列~getRGB传入的应该是x y
Array.pointArray[i][j] = bimg.getRGB(j, i);
}
3.保存文件: 把绘制出来的图片放在硬盘里
首先 在frame上设置按钮 通过监听器跟文件io流连接
//加菜单项
final javax.swing.JMenuItem item1 = new javax.swing.JMenuItem("保存");
final javax.swing.JMenuItem item2 = new javax.swing.JMenuItem("打开");
//加动作命令
item1.setActionCommand("save");
item2.setActionCommand("open");
//建立匿名内部类 并
ActionListener alis = new ActionListener(){
public void actionPerformed(ActionEvent e) {
//给item1和item2设置命令
String command1 = item1.getActionCommand();
String command2 = item2.getActionCommand();
if(command1.equals("save")){
//把图片保存成文件
FileUtil.saveFile("G:\\蓝杰\\first.bmp");
}
if(command2.equals("open")){
//把ispaint设置为true
DrawListener.isPaint = true;
//把文件从硬盘读取出来
int[][] readData =FileUtil.readFile("G:\\蓝杰\\first.bmp");
DrawListener.Point_Array = readData;
//DrawListener.POINT_ARRAY = readData;
System.out.println(readData);
// 刷新drawPanel
drawpanel.updateUI();
}else{
System.out.println("出错了!!");
}
}
};
item1.addActionListener(alis);
item2.addActionListener(alis);
然后:创建保存文件的方法
/**
* 保存文件的方法
* @param path 要保存到的路径
*/
public static void saveFile(String path){
try{
//创建文件输出流
java.io.FileOutputStream fos = new java.io.FileOutputStream(path);
//把他包装成数据流
java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);
//首先写入图片的高度和宽度
dos.writeInt(DrawListener.Point_Array.length);
dos.writeInt(DrawListener.Point_Array[0].length);
//遍历颜色数组把颜色点都写入文件
for(int i =0;i<DrawListener.Point_Array.length;i++)
for(int j = 0;j<DrawListener.Point_Array[i].length;i++){
//把颜色数组的内容写入文件
dos.writeInt(DrawListener.Point_Array[i][j]);
}
//把数据流强制输出 文件流关闭
dos.flush();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
创建读取文件的方法
/**
* 读文件 从硬盘到内存
* @param path 要读入的文件路径
*/
public static int[][] readFile(String path){
try{
//创建文件输入流
java.io.FileInputStream fis = new java.io.FileInputStream(path);
//把他包装成数据流
java.io.DataInputStream dis = new java.io.DataInputStream(fis);
//先读出数组的宽和高 放入新的二维数组里~
int height = dis.readInt();
int width = dis.readInt();
//根据宽和高创建一个新的二维数组
int[][] array = new int[height][width];
//读取颜色把颜色放在新的二维数组里
for(int i=0;i<height;i++)
for(int j = 0;j<width;j++){
array[i][j] = dis.readInt();
}
//只需要关闭输入流即可
fis.close();
return array;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
二、难点分析
1.捕捉屏幕方法中取到二维数组里每点的颜色
这里用了Color()的一种没用过的构造方法
就是 int值表示一个颜色 因为我们要把颜色放进二维数组
所以二维数组里的颜色只能有一个值 就是int
首先从捕捉drawpanel上的像素图像这个函数开始
BufferedImage bimg = rb.createScreenCapture(rec);
需要一个Rectangle
创立Rectangle需要point和drawDim
所以就构造point和drawDim
BufferedImage有一个getRGB的方法 正好可以把它的int值放进颜色数组里
这样就实现了捕捉屏幕(详细代码见 “二、重绘”)
2.关于记录颜色数组是放在接口还是类中的问题
开始时我把 Point_Array放入接口中 但接口中的数组大小不能发生改变
而实际操作中
在读取文件的函数里 获取的数组高度和宽度是放在新建的数组里
//根据宽和高创建一个新的二维数组
int[][] array = new int[height][width];
//读取颜色把颜色放在新的二维数组里
for(int i=0;i<height;i++)
for(int j = 0;j<width;j++){
array[i][j] = dis.readInt();
}
所以在listener里面要把新数组赋给Point_Array 结果出现了问题
后来 就把Point_Array放进了drawlistener里就实现了
三、错误点集合
1. 这个readfile函数里 return有点小技巧
在try里面 return 这个二维数组 在外面 return null
说明 只有try了 才return
2.ispaint的问题
出现整个drawpanel全部是黑色的情况
错点分析:
画布的设置颜色的方法传入的是颜色的一个int 值
g.setColor(new Color(POINT_ARRAY[i][j]));
这句代码 当画面上还没有绘制形状的时候POINT_ARRAY[i][j]都是零 而零表示黑色
所以一开始整个屏幕都是黑色
所以我们在listener里设置了一个布尔型的变量ispaint来判断他是否已经有内容
public static boolean isPaint = false;
在mouserelease()函数的最后 当存入数据到数组中时