fusi0n
fusi0n

Reputation: 1079

Java swing repaint GUI

I am trying to implement an undo / redo functionality in my line drawing/moving/deleting program. I am currently saving each line as a list of points and storing all the lines in a list. After every drawing/moving/deleting operation I will add the new list of lines to my buffer and increment the bufferIterator(counter) to be the last element of the buffer at every mouseReleased action. When I press ESC I am trying to make the current lines variable the previous list of lines and repaint, but the repaint part is not working. Does anyone have any idea what I am doing wrong ?

The code is here:

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

Upvotes: 1

Views: 173

Answers (1)

jzd
jzd

Reputation: 23639

The issue is that you are not adding new objects to the buffer. Each time it is a reference to the same List. So when you get the list at the correct index out of the buffer you get the same list as any other index.

To fix this create a copy of the lines list to add to the buffer instead of adding lines each time.

Something like:

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

Upvotes: 2

Related Questions