撤销绘画程序的方法 [英] Undo method for a paint program

查看:176
本文介绍了撤销绘画程序的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的一个程序中创建一个小画板。这是类:

 类DrawPad扩展JComponent {

图片图片;
Graphics2D图形;
int currentX,currentY,oldX,oldY;

public DrawPad(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY ();
}
});

addMouseMotionListener(new MouseMotionAdapter(){
@Override
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics!= null){
graphics.drawLine(oldX,oldY,currentX,currentY);
}
repaint();
oldX = currentX;
oldY = currentY;
}
});
}

@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(image == null){
image = createImage(getSize()。width,getSize()。height);
graphics =(Graphics2D)image.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image,0,0,null);
}

public void clear(){
graphics.setPaint(Color.white);
graphics.fillRect(0,0,getSize()。width,getSize()。height);
graphics.setPaint(Color.black);
repaint();

$ b $ public void undo(){
//在此恢复以前的图形
}

public void red(){
graphics.setPaint(Color.red);
repaint();
}

public void black(){
graphics.setPaint(Color.black);
repaint();
}

public void magenta(){
graphics.setPaint(Color.magenta);
repaint();
}

public void blue(){
graphics.setPaint(Color.blue);
repaint();
}

public void green(){
graphics.setPaint(Color.green);
repaint();
}

}

我将它添加到JPanel中。绘图本身工作正常。现在我想实现一种撤消方法。我想我可以将当​​前的图形2D对象复制到备份变量中,然后单击撤销按钮,我将用备份对象替换当前对象。
不幸的是没有成功。

我尝试了以下方法:

在mousePressed方法

  addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent e){
graphicsBackup = graphics.create();
oldX = e.getX();
oldY = e.getY();
}
});

在撤消方法中,我尝试将备份变量的引用分配给原始对象。 / p>

  public void undo(){
graphics = graphicsBackup;
repaint();
}

在第二次尝试中,我使用了AffineTransform对象。我在keyPressed方法中调用getTransform来获取当前状态,然后在undo方法中使用setTransform。
也没有效果。你有什么建议如何工作?






解决方案:(增加了一些额外的方法)
$ b

  class DrawPad扩展JComponent {

private Image image;
私人图片背景;
私人Graphics2D图形;
private int currentX,currentY,oldX,oldY;
private final SizedStack<图片> undoStack = new SizedStack<>(12);

public DrawPad(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent e){
saveToStack(image);
oldX = e.getX();
oldY = e.getY();
}
});

addMouseMotionListener(new MouseMotionAdapter(){
@Override
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics!= null){
graphics.drawLine(oldX,oldY,currentX,currentY);
}
repaint();
oldX = currentX;
oldY = currentY;
}
});
}

@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(image == null){
image = createImage(getSize()。width,getSize()。height);
graphics =(Graphics2D)image.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
clear();

g.drawImage(image,0,0,getWidth(),getHeight(),null);

$ b $ public void clear(){
if(background!= null){
setImage(copyImage(background));
} else {
graphics.setPaint(Color.white);
graphics.fillRect(0,0,getSize()。width,getSize()。height);
graphics.setPaint(Color.black);
}
repaint();
}

public void undo(){
if(undoStack.size()> 0){
setImage(undoStack.pop());



private void setImage(Image img){
graphics =(Graphics2D)img.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setPaint(Color.black);
image = img;
repaint();
}

public void setBackground(Image img){
background = copyImage(img);
setImage(copyImage(img));
}

private BufferedImage copyImage(Image img){
BufferedImage copyOfImage = new BufferedImage(getSize()。width,getSize()。height,BufferedImage.TYPE_INT_RGB);
图形g = copyOfImage.createGraphics();
g.drawImage(img,0,0,getWidth(),getHeight(),null);
return copyOfImage;
}

private void saveToStack(Image img){
undoStack.push(copyImage(img));
}

public void red(){
graphics.setPaint(Color.red);
repaint();
}

public void black(){
graphics.setPaint(Color.black);
repaint();
}

public void magenta(){
graphics.setPaint(Color.magenta);
repaint();
}

public void blue(){
graphics.setPaint(Color.blue);
repaint();
}

public void green(){
graphics.setPaint(Color.green);
repaint();


$ / code $ / pre
$ b $ s SizedStack:

  public class SizedStack< T>延伸Stack< T> {

private final int maxSize;

public SizedStack(int size){
super();
this.maxSize = size;
}

@Override
public Object push(Object object){
while(this.size()> maxSize){
this.remove (0);
}
返回super.push((T)对象);
}
}


解决方案

I我自己在一段时间后实施了绘图程序。以下是我如何实现撤消/重做:



我有两个堆栈。 '撤销'堆栈和'重做'堆栈。每次用户绘制东西时,都是这样做的:


  1. 之前应用绘制到图像上的图形,我将图像保存到'撤消'堆栈。

  2. 在应用绘制的图形之后,我再次将图像保存到撤消堆栈。 li>

例如,如果用户想绘制一条线,我将前的当前图像保存到图像的线条。



当用户按下'撤消'时,我只需从'撤消'堆栈弹出顶部图像,并将其绘制到屏幕上。然后我把它放在'重做'堆栈中。



当用户按下'重做'时,'重做'堆栈中的顶部图像被弹出并应用于绘图区域,并放在撤消堆栈的顶部(反向操作)。



编辑:为了将图像推送到堆栈(没有堆栈中的所有对象都是对同一对象的引用),则需要先将图像复制到新图像。像这样的东西(在细节上可能不准确):

  void saveToStack(BufferedImage img){//制作img的副本并穿上堆叠。 
BufferedImage imageForStack = new BufferedImage(img.getWidth(),img.getHeight(),img.getType());
Graphics2D g2d = imageForStack.createGraphics();
g2d.drawImage(img,0,0,null);
undoStack.push(imageForStack);
}

希望这有助于您。


I am trying to create a little drawing pad in one of my programs. This is the class:

class DrawPad extends JComponent {

Image image;
Graphics2D graphics;
int currentX, currentY, oldX, oldY;

public DrawPad() {
    setDoubleBuffered(false);        
    addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            oldX = e.getX();
            oldY = e.getY();
        }
    });

    addMouseMotionListener(new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            currentX = e.getX();
            currentY = e.getY();
            if (graphics != null) {
                graphics.drawLine(oldX, oldY, currentX, currentY);
            }
            repaint();
            oldX = currentX;
            oldY = currentY;
        }           
    });
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (image == null) {
        image = createImage(getSize().width, getSize().height);
        graphics = (Graphics2D) image.getGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        clear();
    }
    g.drawImage(image, 0, 0, null);
}

public void clear() {
    graphics.setPaint(Color.white);
    graphics.fillRect(0, 0, getSize().width, getSize().height);
    graphics.setPaint(Color.black);
    repaint();
}

public void undo() {
    // restore previous graphics here
}

public void red() {
    graphics.setPaint(Color.red);
    repaint();
}

public void black() {
    graphics.setPaint(Color.black);
    repaint();
}

public void magenta() {
    graphics.setPaint(Color.magenta);
    repaint();
}

public void blue() {
    graphics.setPaint(Color.blue);
    repaint();
}

public void green() {
    graphics.setPaint(Color.green);
    repaint();
}

}

I add it to a JPanel. The drawing itself works fine. Now I would like to implement an undo method. I thought I could just copy the current graphics2D object into a backup variable and on click of the undo-button I would replace the current object with the backup object. Unfortunately that didn't work.

I tried the following:

In the mousePressed method I assigned the current value of graphics to the backup variable.

addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        graphicsBackup = graphics.create();
        oldX = e.getX();
        oldY = e.getY();
    }
});

and in the undo method I tried to assign the reference of the backup variable to the original object.

public void undo() {
    graphics = graphicsBackup;
    repaint();
}

In my second try I worked with the AffineTransform Object. I called getTransform in the keyPressed method to get the current state and then setTransform in the undo method. That didn't work either. Do you have any suggestions how it could work?


SOLUTION: (added some additional methods for background etc.)

class DrawPad extends JComponent {

private Image image;
private Image background;
private Graphics2D graphics;
private int currentX, currentY, oldX, oldY;
private final SizedStack<Image> undoStack = new SizedStack<>(12);

public DrawPad() {
    setDoubleBuffered(false);
    addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            saveToStack(image);
            oldX = e.getX();
            oldY = e.getY();
        }
    });

    addMouseMotionListener(new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            currentX = e.getX();
            currentY = e.getY();
            if (graphics != null) {
                graphics.drawLine(oldX, oldY, currentX, currentY);
            }
            repaint();
            oldX = currentX;
            oldY = currentY;
        }
    });
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (image == null) {
        image = createImage(getSize().width, getSize().height);
        graphics = (Graphics2D) image.getGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        clear();
    }
    g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}

public void clear() {
    if (background != null) {
        setImage(copyImage(background));
    } else {
        graphics.setPaint(Color.white);
        graphics.fillRect(0, 0, getSize().width, getSize().height);
        graphics.setPaint(Color.black);
    }
    repaint();
}

public void undo() {
    if (undoStack.size() > 0) {
        setImage(undoStack.pop());
    }
}

private void setImage(Image img) {
    graphics = (Graphics2D) img.getGraphics();
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setPaint(Color.black);
    image = img;
    repaint();
}

public void setBackground(Image img) {
    background = copyImage(img);
    setImage(copyImage(img));
}

private BufferedImage copyImage(Image img) {
    BufferedImage copyOfImage = new BufferedImage(getSize().width, getSize().height, BufferedImage.TYPE_INT_RGB);
    Graphics g = copyOfImage.createGraphics();
    g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
    return copyOfImage;
}

private void saveToStack(Image img) {
    undoStack.push(copyImage(img));
}

public void red() {
    graphics.setPaint(Color.red);
    repaint();
}

public void black() {
    graphics.setPaint(Color.black);
    repaint();
}

public void magenta() {
    graphics.setPaint(Color.magenta);
    repaint();
}

public void blue() {
    graphics.setPaint(Color.blue);
    repaint();
}

public void green() {
    graphics.setPaint(Color.green);
    repaint();
}
}

SizedStack:

public class SizedStack<T> extends Stack<T> {

private final int maxSize;

public SizedStack(int size) {
    super();
    this.maxSize = size;
}

@Override
public Object push(Object object) {
    while (this.size() > maxSize) {
        this.remove(0);
    }
    return super.push((T) object);
}
}

解决方案

I implemented a drawing program myself a while back. Here's how I implemented undo/redo:

I had two stacks. 'Undo' stack and 'redo' stack. Every time the user draws something, this is what I did:

  1. Before applying the graphics drawn to the image, I save the image to the 'undo' stack.
  2. After applying the graphics drawn, I save the image again to the 'undo' stack.

For example, if the user wants to draw a line, I save the current image to the stack before applying the line to the image. And after applying the line, I save it again to the stack.

When the user presses 'undo', I simply pop the top image from the 'undo' stack, and draw it to the screen. Then I put it in the 'redo' stack.

When the user presses 'redo', the top image in the 'redo' stack is popped and applied to the drawing area, and put on top of the 'undo' stack (the reverse operation).

EDIT: In order to push the image onto the stack (without all the objects in the stack being references to the same object), you need to first copy the image to a new image. Something like this (might be inaccurate on the details):

void saveToStack(BufferedImage img){ // makes a copy of img and puts on stack.
    BufferedImage imageForStack = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
    Graphics2D g2d = imageForStack.createGraphics();
    g2d.drawImage(img, 0, 0, null);
    undoStack.push(imageForStack);
}

Hope this helps.

这篇关于撤销绘画程序的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆