画板(重绘)

   画板算是我在学习java过程中第一个完成的迷你项目,现在总结一下它。
   画板实现的第一步就是定义一个JFrame,作为放置按钮以及画布的容器,同时设置它的相关属性:

 

  setTitle("画板");
  setSize(600, 600);
  this.setDefaultCloseOperation(3);
  this.setResizable(false);
  this.setLocationRelativeTo(null);
  // this.setLayout(new FlowLayout());
  this.setLayout(null);
  this.setBackground(Color.WHITE);


   接下来定义一个JPanel,并设置它在JFrame中的坐标位置,以及它的行列数目

 

  JPanel panel = new JPanel();
  panel.setBounds(0, 0, 600, 100);
  panel.setBackground(Color.WHITE);
  panel.setLayout(new GridLayout(2, 5));
  this.add(panel);

  drawpanel.setBounds(0, 100, 600, 500);
  drawpanel.setBackground(Color.WHITE);
  this.add(drawpanel); 

 

之后在面板上添加相应的按钮,我制作的按钮有九个:

 

  JButton btn = new JButton("直线");
  btn.setActionCommand("Line");
  panel.add(btn);
  JButton btn1 = new JButton("曲线");
  btn1.setActionCommand("Curve");
  panel.add(btn1);
  JButton btn2 = new JButton("颜色");
  btn2.setActionCommand("Color");
  panel.add(btn2);
  JButton btn3 = new JButton("圆");
  btn3.setActionCommand("Circle");
  panel.add(btn3);
  JButton btn4 = new JButton("矩形");
  btn4.setActionCommand("Rectangle");
  panel.add(btn4);
  JButton btn5 = new JButton("填充圆");
  btn5.setActionCommand("FillCircle");
  panel.add(btn5);
  JButton btn6 = new JButton("填充矩形");
  btn6.setActionCommand("FillRectangle");
  panel.add(btn6);
  JButton btn7 = new JButton("橡皮");
  btn7.setActionCommand("Eraser");
  panel.add(btn7);
  JButton btn8 = new JButton("图片");
  btn8.setActionCommand("Picture");
  panel.add(btn8);
 

写好面板上的内容之后,就可以添加动作监听器了,也就是作为点击按钮之后的事件处理动作

    ActionListener al = new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    if (e.getActionCommand().equals("Color")) {
     color = javax.swing.JColorChooser.showDialog(null, "颜色选择器",
       Color.BLACK);
     System.out.println("你选择的颜色是" + color);
    } else {
     Item = e.getActionCommand();
     System.out.println("你选择的按钮是:" + Item);
     System.out.println("现在队列中有" + DrawListener.stl.size()
       + "个对象");
    }
   }
  };

 

下面给每个按钮加上这样的监听器,这样每次点击发生时都会调用到相应的动作
  btn.addActionListener(al);
  btn1.addActionListener(al);
  btn2.addActionListener(al);
  btn3.addActionListener(al);
  btn4.addActionListener(al);
  btn5.addActionListener(al);
  btn6.addActionListener(al);
  btn7.addActionListener(al);
  btn8.addActionListener(al);
记得在添加按钮后设置整个面板可见,有一次我放错了可见的设置位置,纠结了一阵
setVisible(true);
此时,还要给之前定义的JPanel加上鼠标监听器,因为我们画图像的时候是在画布上画的,也就是说要对你的鼠标点击以及拖动做出反应。这里要强调一点,必须把drawpanel也传过去,否则绘制的时候会出现坐标偏差,因为系统默认是以JFrame为坐标基准的
  DrawListener dl = new DrawListener(this,drawpanel);
  drawpanel.addMouseListener(dl);
  drawpanel.addMouseMotionListener(dl);
此时,整个面板的定义结束,我们接下来要编辑的就是监听器类
首先定义一个监听器的构造函数,用于在JFrame中实例化对象,并将JFrame以及Drawpanel传过来进行操作
  public DrawListener(DrawFrame df,JPanel drawpanel){
  this.df = df;
  g = drawpanel.getGraphics();
  this.drawpanel = drawpanel;
 }
其中g是一个画布对象,即指你画在画布上的那个东东,可以通过捕获g来设置将要绘制的图像的颜色、形状等。
做完了这些,就要定义鼠标的按下和释放时要执行的动作了
  public void mousePressed(MouseEvent e){
  x1 = e.getX();
  y1 = e.getY();
 }
  public void mouseReleased(MouseEvent e){
  x2 = e.getX();
  y2 = e.getY();
  g.setColor(df.getColor());
  color = g.getColor();
  if(df.getItem().equals("Line")){
   g.drawLine(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
  }
  if(df.getItem().equals("Circle")){
   g.drawOval(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
  }
  if(df.getItem().equals("Rectangle")){
   g.drawRect(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
  }
  if(df.getItem().equals("FillCircle")){
   g.fillOval(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
  }
  if(df.getItem().equals("FillRectangle")){
   g.fillRect(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
  }
  if(df.getItem().equals("Picture")){
   image = Toolkit.getDefaultToolkit().getImage   ("C://workspaces//JavaLessons//src//cn//wx//Excise6//leaf.jpg");
   g.drawImage(image, x1, y1, 100, 100, df.getBackground(), df);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
   }
 }
上方括号内的是图片的绝对路径,需要时候自己写入即可,我上网查了很多图片导入的方法,最后总结出了这个,应该是最简单的图片导入了吧,或者大家可以把图片放在文件目录下,通过相对路径导入。其中特别要注意的是,图片导入的时候一定要把绝对路径的\全部换做//,我当时搞这个抑郁了好一会。
接下来是鼠标拖动时的动作,也就是点击画曲线
  public void mouseDragged(MouseEvent e){
  x2 = e.getX();
  y2 = e.getY();
  g.setColor(df.getColor());
  if(df.getItem().equals("Curve")){
   g.drawLine(x1, y1, x2, y2);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
   stl.add(shape);
   x1 = x2;
   y1 = y2;
  }
 }
下面是点击按钮后拖动鼠标会执行的动作,也就是橡皮
  public void mouseMoved(MouseEvent e){
  x2 = e.getX();
  y2 = e.getY();
  if(df.getItem().equals("Eraser")){
   g.setColor(Color.WHITE);
   g.clearRect(x1, y1, 100, 100);
   Shapes shape = new Shapes(color, df.getItem(), x1, y1, 100, 100);
   stl.add(shape);
   x1 = x2;
   y1 = y2;
  }
 }
到此为止,一个简易的画板就算是完成了,接下来要进行的是画板的重绘,也就是说现在的画布对象只是暂时可见的,一次最小化就会完全消失,因为窗口的每一次弹出都会自己按照代码重新实现,之前所画的东东如果不保存就一定不会再出现,其实这个实现起来很简单,但当时我不理解原理,也弄得很懵懂。首先是定义一个队列,从而能够自动增长存储画布元素
 public interface queueinter<E>{
 //添加对象
 public void add(E e);
 
 //根据索引返回对象值
 public E get(int index);
 
 //得到队列长度
 public int size();
 
 //在指定位置插入一个对象
 public void insert(int index,E e);
 
 //删除一个对象,并返回值
 public E delete(int index);
 
 //在队列的尾部添加另一队列的所有对象
 public void addAll(STList<E> list);
以上是定义了一个接口来规范接下来要写的方法名、返回值、参数类型等,下面是写一个类实现这些方法
 public class STList<E> implements queueinter<E>{
 
 private Object [] obl = new Object[0];
 private int size = obl.length;
 
 //添加对象
 public void add(E e){
  Object [] temp = new Object[obl.length+1];
  temp[obl.length] = e;
  System.arraycopy(obl, 0, temp, 0, obl.length);
  obl = temp;
 }
 
 //根据索引返回对象值
 public E get(int index){
  E e = (E) obl[index];//转型
  return e;
 }
 
 //得到队列长度
 public int size(){
  return obl.length;
 }
 
 //在队列的尾部添加另一队列的所有对象
 public void addAll(STList<E> list){
  Object [] temp = new Object[obl.length+list.size()];
  System.arraycopy(obl, 0, temp, 0, obl.length);
  System.arraycopy(list, 0, temp, obl.length, list.size());
  this.size = obl.length+list.size();
  obl = temp;
 }
 
 //在指定位置插入一个对象
 public void insert(int index,E e){
  Object [] temp = new Object[obl.length];
  System.arraycopy(obl, index, temp, 0, obl.length-index);
  for(int i=index;i<obl.length;i++){
   obl[i] = null;
  }
  obl[index] = e;
  this.size++;
     System.arraycopy(temp, 0, obl, index+1, temp.length);
 }
 
 //删除一个对象,并返回值
 public E delete(int index){
  E e = (E) obl[index];
  for(int i=index;i<obl.length;i++){
   obl[i] = obl[i+1];
  }
  this.size--;
  return e;
 }
 
 public void show(){
  System.out.println(obl);
 }
 
 
同时,定义一个名为Shapes的类,存储所画的图形信息
    public class Shapes {  
    private int x1,y1,x2,y2;  
    private Color color;  
    private String item;  
    public Shapes(Color color,String item,int x1,int y1,int x2,int y2){  
        this.color=color;  
        this.item=item;  
        this.x1=x1;  
        this.y1=y1;  
        this.x2=x2;  
        this.y2=y2;  
    }  
    public int getX1() {  
        return x1;  
    }  
    public void setX1(int x1) {  
        this.x1 = x1;  
    }  
    public int getY1() {  
        return y1;  
    }  
    public void setY1(int y1) {  
        this.y1 = y1;  
    }  
    public int getX2() {  
        return x2;  
    }  
    public void setX2(int x2) {  
        this.x2 = x2;  
    }  
    public int getY2() {  
        return y2;  
    }  
    public void setY2(int y2) {  
        this.y2 = y2;  
    }  
    public Color getColor() {  
        return color;  
    }  
    public void setColor(Color color) {  
        this.color = color;  
    }  
    public String getItem() {  
        return item;  
    }  
    public void setItem(String item) {  
        this.item = item;  
    }  
所有的这些做好后,就是要在JFrame的绘制方法中加入图片已保存信息的输出,也就是画出与之前所画的同样的图形,注意将重绘的方法写在drawpanel里面,因为这样就能够保证每一次重绘画布的时候我们的图形能够在上面显示
   JPanel drawpanel = new JPanel() {
   public void paint(Graphics g) {
    super.paint(g);
    if (null != DrawListener.stl) {
     // 取出队列中保存信息
     for (int i = 0; i < DrawListener.stl.size(); i++) {
      Shapes sp = DrawListener.stl.get(i);
      Color c = sp.getColor();
      if (sp.getItem().equals("Line")|| sp.getItem().equals("Curve")) {
       g.setColor(c);
       g.drawLine(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
      } else if (sp.getItem().equals("Rectangle")) {
       g.setColor(c);
       g.drawRect(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
      } else if (sp.getItem().equals("Circle")) {
       g.setColor(c);
       g.drawOval(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
      } else if (sp.getItem().equals("FillCircle")) {
       g.setColor(c);
       g.fillOval(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
      } else if (sp.getItem().equals("FillRectangle")) {
       g.setColor(c);
       g.fillRect(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
      } else if (sp.getItem().equals("Eraser")) {
       g.setColor(c);
       g.clearRect(sp.getX1(), sp.getY1(),sp.getX2(),sp.getY2());
       } /**else if (sp.getItem().equals("Picture")) {
       image = Toolkit.getDefaultToolkit().getImage("C://workspaces//JavaLessons//src//cn//wx//Excise6//leaf");
       g.drawImage(image, sp.getX1(), sp.getY1(), 100, 100,df.getBackground(),df);
       }*/
     }
    }
   }
  };
起初完成后,我的图片重绘是有问题的,老师说在图片重绘时不能用绝对路径,可以将它放在代码所在的目录下进行引用,即可实现重绘。
通过这次的画板绘制我学习到了很多,很多细微的东西之前只是在听,觉得自己懂了,但是实际操作起来还是有一定难度的,一些小细节不注意就会出错,在编写代码时一定要注意自己能够调错,遇到不理解的错误可以在报错的地方多加几条输出语句查看整个过程是否如预想一般地进行,虽然这可能都不能算是写出一个项目,只是最简单的实现而已,相信有了这一点一滴的积累,我今后的学习会更加顺利~~~~~
                                                                                           
                                                                                                                                                                          艾儿~~

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值