1

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

代码在这里:

    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;
    }
}
4

1 回答 1

2

问题是您没有向缓冲区添加新对象。每次它都是对同一个列表的引用。因此,当您从缓冲区中获取正确索引处的列表时,您将获得与任何其他索引相同的列表。

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

就像是:

 buffer.add(lines);
 lines = new LinkedList<List<Point>(lines);
于 2013-11-04T18:13:11.343 回答