Реализация отмены в графическом редакторе

 
 
 
Сообщения:2
В общем, пишу примитивный графический редактор и хочу реализовать отмену последнего действия. Идея такая: получать картинку до ее изменения и хранить ее в BufferedImage, и при нажатии на кнопку "Отмена" поле для рисования заливается этой самой картинкой. Но почему-то как бы я не делал, у меня в переменную идет картинка после изменения. То есть если я рисую линию, то идет картинка с этой линии, если еще одну, то уже на картинке две линии, хотя картинка должна передаваться до изменений.
Изменен:16 ноя 2016 21:47
 
 
Сообщения:409
См. Паттерн Command
 
 
Сообщения:155
Можно ещё приспособить паттерн "Memento".
public class Solution
{
	public static void main(String[] args)
	{
		SwingUtilities.invokeLater(new Runnable()
		{
			@Override
			public void run()
			{
				JFrame frame = new JFrame("drawing panel");
				frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
				frame.getContentPane().add(new DrawingPanel());
				frame.setSize(700, 500);
				frame.setVisible(true);
				frame.setLocationRelativeTo(null);
			}
		});
	}
}

public class DrawingPanel extends JPanel
{
	public DrawingPanel()
	{
		careTaker = new CareTaker();

		undoButton = new JButton("Undo");
		undoButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				Memento memento = careTaker.get();
				restoreState(memento);

				DrawingPanel.this.repaint();
			}
		});
		add(undoButton);

		addMouseListener(new MouseAdapter()
		{
			@Override
			public void mousePressed(MouseEvent e)
			{
				xPad = e.getX();
				yPad = e.getY();
			}

			@Override
			public void mouseReleased(MouseEvent e)
			{
				dragged = false;
			}
		});

		addMouseMotionListener(new MouseMotionAdapter()
		{
			@Override
			public void mouseDragged(MouseEvent e)
			{
				if(dragged == false)
				{
					careTaker.add(saveState());
					dragged = true;
				}

				Graphics g = buffer.getGraphics();
				Graphics2D g2 = (Graphics2D) g;
				g2.setColor(Color.BLUE);
				g2.drawLine(xPad, yPad, e.getX(), e.getY());

				xPad = e.getX();
				yPad = e.getY();

				DrawingPanel.this.repaint();
			}
		});
	}

	@Override
	protected void paintComponent(Graphics g)
	{
		if(buffer == null)
		{
			buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
			Graphics2D d2 = (Graphics2D) buffer.createGraphics();
			d2.setColor(Color.white);
			d2.fillRect(0, 0, this.getWidth(), this.getHeight());
		}

		g.drawImage(buffer, 0, 0, this);
	}

	private Memento saveState()
	{
		BufferedImage clone = new BufferedImage(buffer.getWidth(), buffer.getHeight(), buffer.getType());
		Graphics g = clone.getGraphics();
		g.drawImage(buffer, 0, 0, null);
		g.dispose();

		return new Memento(clone);
	}

	private void restoreState(Memento memento)
	{
		if(memento != null)
		{
			buffer = memento.getState();
		}
	}

	private JButton undoButton;
	private BufferedImage buffer;
	private CareTaker careTaker;
	private boolean dragged;
	private int xPad;
	private int yPad;
}

public class Memento
{
	public Memento(BufferedImage image)
	{
		state = image;
	}

	public BufferedImage getState()
	{
		return state;
	}

	private final BufferedImage state;
}

public class CareTaker
{
	public void add(Memento state)
	{
		mementoList.add(state);
	}

	public Memento get()
	{
		if(!mementoList.isEmpty())
		{
			return mementoList.remove(mementoList.size() - 1);
		}

		return null;
	}

	private List<Memento> mementoList = new ArrayList<>();
}
 
 
Сообщения:2
vps, огромное спасибо!
 
 
Сообщения:409
Memento здесь не совсем уместен, он хранит состояние объекта, а нужно отменять или повторять действие.
 
 
Сообщения:32
В книжке банды четырёх паттерн Command описан.
Соответственно в классе Command должен быть метод execute и зеркальный ему метод unexe, это вызов execute только, например, с отрицательным параметром
Объекты Command удобнее всего хранить в стеке

Это общий случай, у вас всё гораздо проще, можно просто хранить ваши картинки в стеке без всяких Command
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет