我正在尝试在我的画线/移动/删除程序中实现撤消/重做功能。我目前将每行保存为点列表并将所有行存储在列表中。在每次绘制/移动/删除操作之后,我会将新的行列表添加到我的缓冲区中,并在每个 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;
}
}