2013-11-04 203 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