Java swing重绘GUI

Java swing重绘GUI,java,swing,list,paintcomponent,repaint,Java,Swing,List,Paintcomponent,Repaint,我正在尝试在我的线条绘制/移动/删除程序中实现撤消/重做功能。我目前正在将每一行保存为点列表,并将所有行存储在列表中。在每次绘图/移动/删除操作之后,我会将新的行列表添加到缓冲区中,并在每次mouseerelease操作中增加bufferIterator(计数器)作为缓冲区的最后一个元素。当我按下ESC键时,我试图使当前行变为先前的行和重绘列表,但重绘部分不起作用。有人知道我做错了什么吗 代码如下: public class Kimp { public static void m

我正在尝试在我的线条绘制/移动/删除程序中实现撤消/重做功能。我目前正在将每一行保存为点列表,并将所有行存储在列表中。在每次绘图/移动/删除操作之后,我会将新的行列表添加到缓冲区中,并在每次mouseerelease操作中增加bufferIterator(计数器)作为缓冲区的最后一个元素。当我按下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;
    }
}
公共类Kimp{
公共静态void main(字符串[]args){
JFrame=newjframe(“Kimp!”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
框架设置尺寸(800600);
frame.setLocationRelativeTo(空);
frame.add(新画布面板());
frame.setVisible(true);
}
}
类CanvasPanel扩展了JPanel{
私有列表缓冲区=新的LinkedList();
私有列表行=新建LinkedList();
私有列表点=新建LinkedList();
公共布尔压缩;
public int bufferIterator=0;
公共整数按X=-999;
公共int pressedY=-999;
公共点差;
公共智力差异;
public List pressedLine=new LinkedList();
public List movedLine=new LinkedList();
公共颜色lineColor=Color.BLUE;
公众拉票小组(){
此参数为.setFocusable(true);
this.requestFocusInWindow();
addKeyListener(keyAdapter);
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
@凌驾
公共组件(图形g){
图形2d g2=(图形2d)g;
g2.设置颜色(颜色为白色);
g2.设定行程(新基本行程(3));
g2.fillRect(0,0,getWidth(),getHeight());
用于(列表行:行){
抽绳(绳,g2);
}
抽绳(点,g2);
}
专用空心绘制线(列表点、图形2D g2){
if(points.size()<2)返回;
如果(ctrlPressed){
int line=points.size();
int lineP=pressedLine.size();
//如果线正在移动,请将颜色设置为红色。
如果(行==lineP){
布尔值优先=比较点(points.get(0),按Line.get(0));
布尔秒=比较点(points.get(lineS-1),按Line.get(lineP-1));
布尔第三=比较点(points.get(line/2),按line.get(lineP/2));
如果(第一个和第二个和第三个){
lineColor=Color.RED;
}
}否则{
lineColor=Color.BLUE;
}
}否则{
lineColor=Color.BLUE;
}
点p1=点。获取(0);
对于(int i=1,n=points.size();i=0){
行=buffer.get(索引);
}
重新油漆();
}否则{
int reply=JOptionPane.showConfirmDialog(null,“是否要退出?”,
“退出”,作业窗格。是\否\选项);
if(reply==JOptionPane.YES\u选项){
系统出口(0);
}
}
}else if(ke.getKeyCode()==ke.VK_控件){
ctrlPressed=真;
}else if(ke.getKeyCode()==ke.VK_空间){
系统输出打印项次(“重做”);
//重做
}
} 
@凌驾
公开无效密钥已释放(密钥事件){
if(ke.getKeyCode()==ke.VK_控件){
ctrlPressed=false;
} 
}
};
private MouseAdapter MouseAdapter=new MouseAdapter(){
@凌驾
公共无效鼠标按下(MouseEvent e){
如果(ctrlPressed){
如果(如isMetaDown()){
Point pointPressed=e.getPoint();

对于(int j=0,m=lines.size();j而言,问题在于您没有向缓冲区添加新对象。每次它都是对同一列表的引用。因此,当您从缓冲区中获得具有正确索引的列表时,您将获得与任何其他索引相同的列表

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

比如:

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

lines=new LinkedList进行绘图工作,是否正确填充了缓冲区。是的,新的行列表已添加到缓冲区中。我不知道您是否每次都将相同的对象引用添加到列表中。由于这些行不是新列表,您可能会一次又一次地将相同的引用添加到缓冲区中。确实如此这是因为当我设置它时,我只是向缓冲区添加了一个新的行列表,并且我希望bufferIterator在我添加新行之后一直指向最后一个元素。当我尝试撤消时,我会分配上一个“状态”作为行中的变量,然后尝试用这些重新绘制面板。这是有道理的,我想我发现了问题,请看我编辑的答案。非常感谢,这是有效的。虽然我只能撤消一个操作。我检查了代码并打印出索引变量。它只减少了一个。而不是每次按下esc时减少一个sed。知道为什么吗?是的,你需要实际减少每个按键的值,而不是硬编码一个-1。bufferIterator也是如此;bufferIterator代替了-1而不是KeyPressed,我用了bufferIterator,因为在其他情况下,效果是在我再次按ESC键时显示的,不是立即显示的。不过,非常感谢你的帮助!R真的很感激!:)