撤消JFrame

时间:2017-06-22 13:02:22

标签: java swing user-interface

我正在JFrame上绘制一些物体,例如圆圈,矩形和它们之间的弧线。

我想知道如何实现 Undo 按钮,记住我发现的那些按钮是针对文本字段并在其中写入的。

我没有要显示的代码,我希望收到有关如何实现它的建议。是否可以“注册”最后发生的事件然后将其删除?

我有一个关于删除圈子的非常简单的代码。它只适用于他们,我知道这是完全错误的,因为我可以有其他事件,如矩形绘制或它们之间的弧。

感谢任何帮助。

2 个答案:

答案 0 :(得分:5)

您可以将Shape个对象存储在List中,让面板从此List中绘制每个形状。

"撤消" action只是移除最后一个元素并重新绘制面板。

以下示例包含用于在随机位置创建矩形和椭圆的按钮,以及着名的"撤消"按钮让你明白了。

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;

public class DrawingUndo {

    List<Shape> shapes = new ArrayList<>();

    public DrawingUndo() {

        final Random randomizer = new Random();

        JFrame frame = new JFrame("Undoable drawings");

        JToolBar bar = new JToolBar();

        final JPanel undoPanel = new UndoPanel();

        JButton addRectangleButton = new JButton("Rectangle");
        addRectangleButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {

                int randomX = 5 + randomizer.nextInt(100);
                int randomY = 5 + randomizer.nextInt(100);
                Rectangle shape = new Rectangle();
                shape.setBounds(randomX, randomY, 30, 20);
                shapes.add(shape);
                undoPanel.repaint();

            }
        });

        JButton addEllipseButton = new JButton("Ellipse");

        addEllipseButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {

                int randomX = 5 + randomizer.nextInt(100);
                int randomY = 5 + randomizer.nextInt(100);
                Ellipse2D shape = new Ellipse2D.Double(randomX, randomY, 80, 30);
                shapes.add(shape);
                undoPanel.repaint();

            }
        });

        JButton undoButton = new JButton("Undo");

        undoButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {

                if (!shapes.isEmpty()) {

                    shapes.remove(shapes.size() - 1);
                    undoPanel.repaint();

                }

            }
        });

        bar.add(addRectangleButton);
        bar.add(addEllipseButton);
        bar.add(Box.createHorizontalGlue());
        bar.add(undoButton);

        frame.add(bar, BorderLayout.NORTH);
        frame.add(undoPanel, BorderLayout.CENTER);

        frame.setSize(400, 200);

        frame.setVisible(true);
    }

    public static void main(final String[] args) {

        new DrawingUndo();
    }

    private class UndoPanel extends JPanel {

        @Override
        public void paintComponent(final Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            for (Shape shape : shapes) {

                g2d.draw(shape);// or g2d.fill(shape) to have its interior filled
            }
        }

    }

}

请注意,Shape并不像颜色那样。

如果您需要这样的东西,请创建一个包含Shape和其他所需参数的包装类,并使用此类对象的列表而不是简单的Shape对象。

答案 1 :(得分:0)

正如@fujy所说,看看Command设计模式(https://sourcemaking.com/design_patterns/command)。高级别的想法是,每次要更改某些内容时,都会创建命令。每个命令都有两个方法 do undo 。执行后,您应该将命令存储在队列(或其他一些数据结构)中。通过按时间顺序遍历命令,您可以执行撤消并实现按钮。 命令对象应包含有关如何执行操作以及如何重做操作的所有信息。例如,它应该包含 newFieldValue oldFieldValue ...还有其他方法可以实现 undu 概念,但我觉得这个很简单和通用 - 它不依赖于您使用的技术。