如何有效地为WinForms图像/绘图应用程序实现undo,redo

时间:2018-03-12 12:21:58

标签: c# vb.net winforms undo redo

我有一个WinForms图像/绘图应用程序。

该应用程序允许用户执行以下操作:

  • 加载/导入图片
  • 保存图片
  • 旋转,裁剪图片
  • 更改像素或区域的颜色

如何在高效方法中为多个操作实现撤消/重做功能? 我应该处理哪个鼠标事件?

我想避免将整个内容保存在图片框(加载图片的位置)中,因为它可能会占用大量内存。

谢谢。

1 个答案:

答案 0 :(得分:2)

我见过实现撤消/重做的最好方法是使用“命令”模式。

每个可以执行的操作都应该实现为一个继承自基类Command类或实现ICommand接口的类。该类应具有ExecuteUndo方法,其中Execute对数据执行操作,并存储撤消操作所需的任何信息。 Undo使用存储的有关要撤消的更改的信息。

如果您只想要一个简单的系统,只能撤消/重做上一次操作,只需保留一个存储上次运行命令的lastCommand字段,并在其上调用Undo时需要的。

如果你想要一些更复杂的东西,有多个撤消级别,请保留一个有序的命令列表,你可以像Stack那样对待。每个执行的Command都被执行,并放置在堆栈的顶部,一些变量指向最后一个命令。在撤消操作时,请在Undo上调用lastCommand,然后将其设置为Command。要重做操作,只需在下一个命令上再次调用Execute,然后向上移动指针。您必须确保当您不在堆栈的“顶部”时运行的任何Command使其无效并在其之前删除操作。

如果你愿意的话,你可以通过命令合并等奇特的东西获得更高级的效果。

有关可以更改单个像素的Command所做的事情的示例(全部来自内存,无法访问Visual Studio,请原谅任何语法错误)。

由于您没有指定语言,我将使用C#,但这也可以在VB.NET中轻松完成。

public class ChangePixelCommand : ICommand
{    
    private Color _previousColor;
    private int x;
    private int y;

    public void Execute(Bitmap image, int x, int y, Color color)
    {
        // record the data needed to undo this operation.
        _previousColor = image.GetPixel(x, y);
        _x = x;
        _y = y;

        // update the image.
        image.SetPixel(x, y, color);
    }

    public void Undo(Bitmap image)
    {
        //  Use the data we saved earlier to put the pixel back the way it was.
        image.SetPixel(_x, _y, _previousColor);
    }
}

要在上面的“简单”方法中使用它,你可以这样做:

// Change a pixel.
lastCommand = new ChangePixelCommand(myImage, 
                                     Control.MousePosition.X,
                                     Control.MousePosition.Y, 
                                     Colors.Red);
lastCommand.Execute();

// Undo the change
lastCommand.Undo();

对于更改区域,您可以只存储更改的矩形的边界,以及之前该区域的小型快照。

对于旋转,它只是旋转角度。

我不确定为什么有人会想要“撤消”保存,但如果真的需要,你可以存储文件名并删除文件。恢复文件的先前内容虽然......可能会变得棘手。