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