2013-11-04 150 views
1

我想在我的绘图/移动/删除程序中实现撤消/重做功能。我目前将每行保存为点列表并将所有行存储在列表中。在每次绘图/移动/删除操作之后,我会将新的行列表添加到我的缓冲区,并在每次mouseReleased操作时增加bufferIterator(counter)作为缓冲区的最后一个元素。当我按下ESC时,我正在尝试使当前行变为先前的行列表并重新绘制,但重绘部分不起作用。有谁知道我做错了什么?Java swing repaint GUI

的代码是在这里:

public class Kimp { 
    public static void main(String[] args) { 
     JFrame frame = new JFrame("Kimp!"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(800, 600); 
     frame.setLocationRelativeTo(null); 
     frame.add(new CanvasPanel()); 
     frame.setVisible(true); 
    } 
} 

class CanvasPanel extends JPanel { 
    private List<List<List<Point>>> buffer = new LinkedList<List<List<Point>>>(); 
    private List<List<Point>> lines = new LinkedList<List<Point>>(); 
    private List<Point> points = new LinkedList<Point>(); 
    public boolean ctrlPressed; 
    public int bufferIterator = 0; 
    public int pressedX = -999; 
    public int pressedY = -999; 
    public int differenceX; 
    public int differenceY; 
    public List<Point> pressedLine = new LinkedList<Point>(); 
    public List<Point> movedLine = new LinkedList<Point>(); 
    public Color lineColor = Color.BLUE; 

    public CanvasPanel() { 
     this.setFocusable(true); 
     this.requestFocusInWindow(); 
     addKeyListener(keyAdapter); 
     addMouseListener(mouseAdapter); 
     addMouseMotionListener(mouseAdapter); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 

     Graphics2D g2 = (Graphics2D) g; 
     g2.setColor(Color.WHITE); 
     g2.setStroke(new BasicStroke(3)); 
     g2.fillRect(0, 0, getWidth(), getHeight()); 

     for (List<Point> line : lines) { 
      drawLine(line, g2); 
     } 
     drawLine(points, g2); 
    } 

    private void drawLine(List<Point> points, Graphics2D g2) { 
     if (points.size() < 2) return; 

     if (ctrlPressed) { 
      int lineS = points.size(); 
      int lineP = pressedLine.size(); 
      //Set the color to RED, if the line is being moved. 
      if (lineS == lineP) { 
       boolean first = comparePoints(points.get(0), pressedLine.get(0)); 
       boolean second = comparePoints(points.get(lineS - 1), pressedLine.get(lineP - 1)); 
       boolean third = comparePoints(points.get(lineS/2), pressedLine.get(lineP/2)); 
       if (first && second && third) { 
        lineColor = Color.RED; 
       } 
      } else { 
       lineColor = Color.BLUE; 
      } 
     } else { 
      lineColor = Color.BLUE; 
     } 

     Point p1 = points.get(0); 

     for (int i=1, n=points.size(); i<n; i++) { 
      Point p2 = points.get(i); 

      g2.setColor(lineColor); 
      g2.drawLine(p1.x, p1.y, p2.x, p2.y); 

      p1 = p2; 
     } 
    } 

    private KeyAdapter keyAdapter = new KeyAdapter() { 

     @Override 
     public void keyPressed(KeyEvent ke) { 
      if(ke.getKeyCode() == ke.VK_ESCAPE) { 
       System.out.println("ESC PRESSED"); 

       if (bufferIterator != 0) { 
        System.out.println("UNDOING!"); 
        //UNDO 
        lines = new LinkedList<List<Point>>(); 
        int index = bufferIterator - 1; 
        if (index >= 0) { 
         lines = buffer.get(index); 
        } 
        repaint(); 

       } else { 
        int reply = JOptionPane.showConfirmDialog(null, "Do you want to exit?", 
          "Exit", JOptionPane.YES_NO_OPTION); 
        if (reply == JOptionPane.YES_OPTION) { 
         System.exit(0); 
        } 
       } 
      } else if(ke.getKeyCode() == ke.VK_CONTROL) { 
       ctrlPressed = true; 
      } else if (ke.getKeyCode() == ke.VK_SPACE) { 
       System.out.println("REDOING"); 
       //REDO 
      } 
     } 

     @Override 
     public void keyReleased(KeyEvent ke) { 
      if(ke.getKeyCode() == ke.VK_CONTROL) { 
       ctrlPressed = false; 
      } 
     } 
    }; 

    private MouseAdapter mouseAdapter = new MouseAdapter() { 
     @Override 
     public void mousePressed(MouseEvent e) { 


      if (ctrlPressed) { 
       if (e.isMetaDown()) { 
        Point pointPressed = e.getPoint(); 
        for (int j=0, m=lines.size(); j<m; j++) { 
         List<Point> line = lines.get(j); 
         for (int i=0, n=line.size(); i<n; i++) { 
          Point pt = line.get(i); 
          //This is, to allow a small margin of missing, but still only take 1 point. 
          if (pointPressed.x - pt.x <= 1 && pointPressed.y - pt.y <= 1) { 
           //Only the first point will be "the point clicked". 
           if (pressedX == -999 && pressedY == -999) { 
            pressedX = pt.x; 
            pressedY = pt.y; 
            pressedLine = line; 
           } 
          } 
         } 
        } 
        for (int x = 0, r = lines.size(); x < r; x++) { 
         int lenA = lines.get(x).size(); 
         int lenB = pressedLine.size(); 
         if (lenA == lenB) { 
          boolean first = comparePoints(lines.get(x).get(0), pressedLine.get(0)); 
          boolean second = comparePoints(lines.get(x).get(lenA - 1), pressedLine.get(lenB - 1)); 
          boolean third = comparePoints(lines.get(x).get(lenA/2), pressedLine.get(lenB/2)); 

          if (first && second && third) { 
           lines.remove(x); 
           buffer.add(lines); 
           repaint(); 
           break; 
          } 
         } 
        } 
       } else { 
        Point pointPressed = e.getPoint(); 
        for (int j=0, m=lines.size(); j<m; j++) { 
         List<Point> line = lines.get(j); 
         for (int i=0, n=line.size(); i<n; i++) { 
          Point pt = line.get(i); 
          //This is, to allow a small margin of missing, but still only take 1 point. 
          if (pointPressed.x - pt.x <= 1 && pointPressed.y - pt.y <= 1) { 
           //Only the first point will be "the point clicked". 
           if (pressedX == -999 && pressedY == -999) { 
            pressedX = pt.x; 
            pressedY = pt.y; 
            pressedLine = line; 
           } 
          } 
         } 
        } 
       } 

      } else { 
       points.add(e.getPoint()); 
       repaint(); 
      } 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 

      Point pointDragged = e.getPoint(); 
      if (ctrlPressed) { 
       differenceX = pointDragged.x - pressedX; 
       differenceY = pointDragged.y - pressedY; 

       //Create the moved line 
       for (Point p : pressedLine) { 
        movedLine.add(new Point(p.x + differenceX , p.y + differenceY)); 
       } 

       for (int i=0, n=lines.size(); i<n; i++) { 
        int lineS = lines.get(i).size(); 
        int lineP = pressedLine.size(); 
        //Choose 3 points in order to not go through all of them 
        boolean first = comparePoints(lines.get(i).get(0), pressedLine.get(0)); 
        boolean second = comparePoints(lines.get(i).get(lineS - 1), pressedLine.get(lineP - 1)); 
        boolean third = comparePoints(lines.get(i).get(lineS/2), pressedLine.get(lineP/2)); 
        if (first && second && third) { 
         lines.set(i, movedLine); 
         pressedX = pressedX + differenceX; 
         pressedY = pressedY + differenceY; 
         pressedLine = movedLine; 
         movedLine = new LinkedList<Point>(); 
         repaint(); 
         break; 
        } 
       } 

      } else { 
       points.add(pointDragged); 
       repaint(); 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 

      if (points.size() > 1) { 
       lines.add(points); 
       points = new LinkedList<Point>(); 
      } 
      //Add the current canvas to buffer 
      buffer.add(lines); 

      System.out.println("Buffer size:"); 
      System.out.println(buffer.size()); 
      System.out.println(buffer.get(buffer.size() - 1)); 
      bufferIterator = buffer.size() - 1; 

      pressedX = -999; 
      pressedY = -999; 

     } 
    }; 

    public boolean comparePoints (Point p1, Point p2) { 
     if (p1.x == p2.x && p1.y == p2.y) { 
      return true; 
     } 
     return false; 
    } 
} 
+0

是否拉丝加工,是被正确填充缓冲。 –

+0

是的,新的行列表被添加到缓冲区。 – fusi0n

+1

我不知道你是否每次添加相同的对象引用列表。由于这些行不是新的List,因此您可能会一遍又一遍地向缓冲区添加相同的引用。 –

回答

2

的问题是,你是不是添加新对象缓冲区。每次都是对同一个List的引用。所以当你从缓冲区中得到正确索引的列表时,你会得到与其他索引相同的列表。

若要解决此问题,请创建行列表的副本以添加到缓冲区,而不是每次添加行。

喜欢的东西:

buffer.add(lines); 
lines = new LinkedList<List<Point>(lines); 
+0

这是因为当我设置它时,我只是添加了一个新的行列表缓冲区,我希望bufferIterator始终指向最后一个元素,我已经添加了一个新行。当我尝试UNDO时,我将先前的“状态”指定为行变量,然后尝试用这些重新绘制面板。 – fusi0n

+0

这是有道理的,我想我发现了这个问题,但看看我编辑的答案。 – jzd

+0

非常感谢,这是行得通的。虽然我只能撤消一项操作。我检查了代码并打印出索引变量。它只是减少一个。每次按Esc都不会一次。任何想法为什么是这样? – fusi0n