画图板总结

在蓝杰上了几节课后就开始了画图板的开发,从一开始简单的界面到能够添加各种颜色工具图片面板,到实现重绘,再到现在的实现保存文件和打开文件,经历了一个漫长的时间,现在的画图板还有许多的不足之处,我觉得最大的问题是(1)实现了保存打开功能后我原本的布局有问题了(原来用的是边框布局,现在改为了流式布局),画布取不到,不知道什么问题,所以现在的画图板布局不是很合理,看着不舒服。(2)我想添加下拉菜单选项的监听器,但是没有找到,最后就将菜单的选项只留下了保存和打开。画图板还有许多的不足之处,我会慢慢修改,使之优化。

这是原先的画板:<!--StartFragment -->

<!--StartFragment -->

这是现在的面板:<!--StartFragment -->
以下是画图板DrawBoard的代码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
/**
 * 窗体类
 * @author Administrator
 *
 */
public class DrawBoard extends JFrame implements Config {
    //定义属性
 private Graphics g;
 private JPanel drawPanel;
    /**
     * 主函数
     * @param args
     */
 public static void main(String[] args) {
  //创建对象
  DrawBoard ds = new DrawBoard();
  //调用显示窗体的方法
  ds.dra();
 }
    /**
     * 显示窗体的方法
     */
 public void dra() {
  this.setTitle("未命名 - 画图");// 设置窗体的标题
  this.setSize(FRAME_WIDTH, FRAME_HEIGHT);//设置画板大小
  this.setResizable(false);//不可改变画板大小
  this.setLocationRelativeTo(null);// 设置窗体的位置
  this.setDefaultCloseOperation(3);// 设置窗体关闭时是否退出
给窗体添加菜单栏的方法
//createMenuBar();
  // 创建工具,颜色,画板面板
  ToolPanel toolPanel = new ToolPanel();
  ColorPanel colorPanel = new ColorPanel();
  //创建一块面板放置工具面板,颜色面板,保存,打开按钮
  JPanel panel =  new JPanel();
  panel.add(colorPanel);
  panel.add(toolPanel); 
  //给窗体设置流式布局
  FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
  this.setLayout(fl);
  // 创建用来绘图的面板
  drawPanel = new MyPanel();
  //给画图面板设置颜色
  drawPanel.setBackground(Color.WHITE);
  //给画图面板设置大小
  drawPanel.setPreferredSize(new Dimension(DRAW_WIDTH, DRAW_HEIGHT));
  //将面板添加到窗体上
  this.add(panel);
  this.add(drawPanel);
  //设置窗体可见
  this.setVisible(true);
  //获取画布对象
  g = drawPanel.getGraphics();
  //实例化一个画图事件处理类对象
  DrawListener tl = new DrawListener(toolPanel,colorPanel,g);
  //给drawPanel添加鼠标监听器方法,并且绑定事件处理类对象
  drawPanel.addMouseListener(tl);
  //给drawPanel添加鼠标移动监听器方法,并且绑定事件处理类对象
  drawPanel.addMouseMotionListener(tl);
  // 给窗体加鼠标监听器
  DrawListener lis = new DrawListener( toolPanel,colorPanel,g);
  drawPanel.addMouseListener(lis);
  
        //******************************匿名内部类************************************//
  MenuListener ml = new MenuListener(){
   @Override
   public void menuCanceled(MenuEvent arg0) {
    // TODO Auto-generated method stub
    
   }
   @Override
   public void menuDeselected(MenuEvent arg0) {
    // TODO Auto-generated method stub
    
   }
   @Override
   public void menuSelected(MenuEvent e) {
    // TODO Auto-generated method stub
    JMenu m = (JMenu)e.getSource();//获取事件源
    String str = m.getActionCommand();
    //判断选择的游戏方式
    if(str.equals("保存")){
     FileUtil.saveFile("H:\\aa\\test.bmp");
     System.out.println("BMP图片保存完毕!");
    }else if(str.equals("打开")){
     DrawListener.isPaint = true;
     // 读取文件,得到二位数组
     int[][] readData = FileUtil.readFile("H:\\aa\\test.bmp");
     DrawListener.data = readData;
     // 刷新drawPanel
     drawPanel.updateUI();
     System.out.println("BMP图片已打开!");
    }else{
     System.out.println("出错啦!");
    }
   }};
   //给菜单选项添加监听器
   JMenuBar jmb = new JMenuBar();
   this.setJMenuBar(jmb);
   JMenu savemenu= new JMenu("保存");
   jmb.add(savemenu);
   savemenu.addMenuListener(ml);
   JMenu openmenu= new JMenu("打开");
   jmb.add(openmenu);
   openmenu.addMenuListener(ml);
  
  //********************************************************************************//
 
 
 /**
  * 创建菜单栏的方法,并且把菜单栏添加到窗体上
  */
 public void createMenuBar() {
  // 创建菜单条对象
  JMenuBar bar = new JMenuBar();
  String[] menus = { "文件", "颜色", "帮助" };
  String[][] menuItems = { { "新建", "打开", "保存", "退出" }, { "编辑颜色" },
    { "帮助主题", "关于画图" } };
  for (int i = 0; i < menus.length; i++) {
   JMenu menu = new JMenu(menus[i]);
   for (int j = 0; j < menuItems[i].length; j++) {
    JMenuItem menuItem = new JMenuItem(menuItems[i][j]);
    menu.add(menuItem);//将下拉菜单添加到菜单上
    menuItem.setActionCommand(menuItems[i][j]);//获取点击下拉菜单上对象的命令
   } 
   bar.add(menu);//将菜单添加到菜单条上
  }
  this.setJMenuBar(bar);// 把菜单条添加到窗体上
  
  
 }
 /**
  * 重新绘制形状的方法
  * @param g 画布对象
  */
 public void drawShape(Graphics g) {
  // 得到drawPanel的背景色
  Color bgColor = drawPanel.getBackground();
     //设置一个变量存储颜色值
  int bgNum = bgColor.getRGB();
  // 遍历二位数组,取出每个像素点的颜色
  for (int i = 0; i < DrawListener.data.length; i++) {
   for (int j = 0; j < DrawListener.data[i].length; j++) {
    int num = DrawListener.data[i][j];
    if (bgNum != num) {
     // 创建颜色对象
     Color color = new Color(num);
     //设置颜色
     g.setColor(color);
     //画每个像素点
     g.drawLine(j, i, j, i);
    }
   }
  }
 }
   
 
 //其他类,一个类中可以有一个以上的类
 class MyPanel extends JPanel {
  /**
   * 重写父类绘制窗体的方法
   */
  public void paint(Graphics g) {
   // 调用父类的方法
   super.paint(g);
   if (DrawListener.isPaint) {
    // 调用绘制方法
    drawShape(g);
   }
  }
 }
}
/
实现保存打开的代码:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileUtil implements Config {
 /**
  * 将图片数据保存到指定的位置
  *
  * @param path
  *            : 要保存数据的位置
  */
 public static void saveFile(String path) {
  try {
   // 创建文件输出流对象
   FileOutputStream fos = new FileOutputStream(path);
   // 将输出流包装成可写基本类型的数据流
   DataOutputStream dos = new DataOutputStream(fos);
   // 写图片的高度和宽度
   dos.writeInt(DrawListener.data.length);
   dos.writeInt(DrawListener.data[0].length);
   // 遍历二维数组,写数据
   for (int i = 0; i < DrawListener.data.length; i++) {
    for (int j = 0; j < DrawListener.data[i].length; j++) {
     int num = DrawListener.data[i][j];
     // 写数据
     dos.writeInt(num);
    }
   }
            //将输出流清空
   dos.flush();
   //将输出流关闭
   fos.close();
  } catch (Exception ef) {
   ef.printStackTrace();
  }
 }
 /**
  * 读取文件中的数据
  *
  * @param path
  *            要读取的文件
  * @return 将读取到的数据作为二位数组返回
  */
 public static int[][] readFile(String path) {
  // 创建文件输入流
  try {
   //创建文件输入流对象
   FileInputStream fis = new FileInputStream(path);
   //将文件输入流包装成可写基本类型的数据流
   DataInputStream dis = new DataInputStream(fis);
   // 读取高度和宽度
   int height = dis.readInt();
   int width = dis.readInt();
   // 定义二维数组
   int[][] readData = new int[height][width];
   //循环读取每个像素点
   for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
     // 将数据读入数组
     readData[i][j] = dis.readInt();
    }
   }
   //关闭输入流
   fis.close();
   //返回二维数组
   return readData;
  } catch (Exception ef) {
   ef.printStackTrace();
  }
  return null;
 }
}
/
监听器类的代码 :
将鼠标动作分为两种,一类是鼠标点击,一类是鼠标拖动
public class DrawListener extends MouseAdapter implements Config {
 //定义属性
 private int x1, y1, x2, y2, x3, y3, x4, y4;// 定义存储鼠标按下和释放时的坐标
 public static boolean isPaint = false;// 是否需要重绘
 private ToolPanel tp;
 private ColorPanel cp;
 private Graphics g;
 private Color color;
 private Robot robot;//机器人对象,自动开始 
 //用来保存数据的二维数组 数组的下标表示每个像素点的坐标,数组中的元素表示每个坐标点的颜色
 public static int[][] data;
 /**
  * 构造函数
  * @param tp 工具面板
  * @param cp  颜色面板
  * @param g  画布
  */
 public DrawListener(ToolPanel tp, ColorPanel cp, Graphics g) {
   // 赋值
  this.tp = tp;
  this.cp = cp;
  this.g = g;
 // 创建对象时可能抛出异常,所以不能直接在定义属性的时候创建
  try {
   robot = new Robot();//创建机器人对象
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 // 鼠标按下时执行的方法
 public void mousePressed(MouseEvent e) {
  x1 = e.getX();
  y1 = e.getY();
  if(e.getButton()==1){
   color = cp.getBColor();
  }else if(e.getButton()==3){
   color = cp.getFColor();
  }
 }
 
 public void mouseDragged(MouseEvent e) {
  // 判断是否需要按下拖动事件
  if (tp.getItem().equals("BrushTool")
    || tp.getItem().equals("PencilTool")
    || tp.getItem().equals("EraserTool")
    || tp.getItem().equals("AtomizerTool")) {
   // 获取坐标
   x2 = e.getX();
   y2 = e.getY();
   Shape shape = null;
   // 判断选择的是哪一个图形,然后创建不同的对象
   if (tp.getItem().equals("BrushTool")) {
    // 使用刷子
    shape = new ShapeBrush(x1, y1, x2, y2, color);
   } else if (tp.getItem().equals("PencilTool")) {
    // 使用铅笔
    shape = new ShapeLine(x1, y1, x2, y2, color);
   } else if (tp.getItem().equals("EraserTool")) {
    // 使用橡皮
    shape = new ShapeEraser(x1, y1, x2, y2, color);
   } else if (tp.getItem().equals("AtomizerTool")) {
    //使用喷枪
    shape = new ShapeAtomizer(x1, y1, x2, y2, color);
   }
   // 开始画图形
   shape.draw(g);
   // 交换坐标
   x1 = x2;
   y1 = y2;
  }
 }
 // 鼠标释放时执行的方法
 public void mouseReleased(MouseEvent e) {
   x2 = e.getX();
   y2 = e.getY();
   if (tp.getItem().equals("LineTool") || tp.getItem().equals("RectTool")
     || tp.getItem().equals("RoundTool")
     || tp.getItem().equals("RoundRectTool")
     || tp.getItem().equals("PolygonTool")) {
    Shape shape = null;
    if (tp.getItem().equals("LineTool")) {
     // 判断是否是直线,开始绘制直线了s
     shape = new ShapeLine(x1, y1, x2, y2,color);
    } else if (tp.getItem().equals("RectTool")) {
     if(x2>x1&&y2>y1){
     // 判断是否是矩形,开始绘制矩形了
      shape = new ShapeRect(x1, y1, x2, y2, color);
     }else if(x2<x1&&y2<y1){
      shape = new ShapeRect(x2,y2,x1,y1,color);
     }else if(x2>x1&&y2<y1){
      shape = new ShapeRect(x1,y2,x2,y1,color);
     }else if(x2<x1&&y2>y1){
      shape = new ShapeRect(x2,y1,x1,y2,color);
     }
     
    } else if (tp.getItem().equals("RoundTool")) {
     if(x2>x1){
      if(y2>y1){
     // 判断是否是圆形,开始绘制圆形了
         shape = new ShapeOval(x1, y1, x2, y2, color);
         }else{
      shape = new ShapeOval(x1,y2,x2,y1,color);
      }
     }else if(x2<x1){
      if(y2<y1){
          shape = new ShapeOval(x2,y2,x1,y1,color);
      }else{
       shape = new ShapeOval(x2,y1,x1,y2,color);
       }
      }
    } else if (tp.getItem().equals("RoundRectTool")) {
     if(x2>x1&&y2>y1){
     // 开始绘制圆矩形
     shape = new ShapeRoundRect(x1, y1, x2, y2, color);
     }else if(x2<x1&&y2<y1){
      shape = new ShapeRoundRect(x2,y2,x1,y1,color);
     }else if(x2>x1&&y2<y1){
      shape = new ShapeRoundRect(x1,y2,x2,y1,color);
     }else if(x2<x1&&y2>y1){
      shape = new ShapeRoundRect(x2,y1,x1,y2,color);
     }
     //绘制多边形
    } else if (tp.getItem().equals("PolygonTool")) {
     //x1,y1,x2,y2没按下和释放一次鼠标都会获取新值,所以用x3,y3,x4,y4
     if (x3 == 0) {//如果x3的值为0,则代表要画的是第一条直线
      x3 = x1;//将鼠标按下和释放时获取的坐标分别赋给x3,y3,x4,y4
      y3 = y1;
      x4 = x2;
      y4 = y2;
      // 开始绘制多边形
      shape = new ShapePolygon(x3, y3, x4, y4, color);
     
     }else{//如果x3的值不是0,则代表之前已经画过直线了,接下来继续画直线
      shape = new ShapePolygon(x4, y4, x2, y2, color);
      //第一组坐标(x4,y4)为画上一条直线时的第二组坐标,第二组坐标为本次画直线获取的第二组坐标
      x4 = x2;//将释放鼠标时获取的坐标(x2,y2)赋给下一次画直线的第一组坐标(起始坐标)
      y4 = y2;
      if((x4-x3 < 5 && x4-x3>-5) && (y4-y3< 5 && y4-y3 > -5)){
       //判断最后一次按下和释放鼠标时获取的x,y坐标之差是否小于5
       x3 = 0;//将直线的初始值设为x3=0,x4=0;重新画多边形
       y3 = 0;
      }
     }
    }
    //System.out.println(null==shape);
    // 调用画图形的方法
    shape.draw(g);
    // 每绘制一次就将整个drawPanel区域内的所有像素点保存起来
    // 得到事件源对象
    Object obj = e.getSource();
    JPanel drawPanel = (JPanel) obj;
    // 得到drawPanel的左上角的点
    Point point = drawPanel.getLocationOnScreen();
    // 得到drawPanel的大小
    Dimension dim = drawPanel.getPreferredSize();
    // 创建矩形区域对象,刚好截取drawPanel在屏幕上所占据的区域
    Rectangle rect = new Rectangle(point, dim);
    // 从屏幕上获取像素区域,得到一个缓存区的图像对象
    BufferedImage img = robot.createScreenCapture(rect);
    data = new int[dim.height][dim.width];
    // 将缓存区的图像对象中的每一个像素的颜色保存起来
    for (int i = 0; i < data.length; i++) {
     for (int j = 0; j < data[i].length; j++) {
      // 得到每个点的颜色(用数字表示的颜色),存入二维数组
      data[i][j] = img.getRGB(j, i);
     }
    }
    isPaint = true;
   }   
  }
}
以上是一些代码和注释以及出现的问题,都需进一步的学习改善,希望大家不吝赐教~~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值